﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Noris.Schedule.Support.Sql;
using System.Data.SqlTypes;
using System.Data.SqlClient;
using Noris.Schedule.Support.Core;

namespace Noris.Schedule.Support.Green
{
	#region CLASS Repository
	/// <summary>
	/// Třída repozitory = řeší správu dat repozitory greenu.
	/// Obsahuje jednotlivé prvky = datové entity.
	/// Třída Repository obsahuje jeden singleton, který obsahuje všechna data.
	/// </summary>
	public partial class Repository
	{
		#region SINGLETON Current
		/// <summary>
		/// Aktuální instance repozitory
		/// </summary>
		private static Repository Current
		{
			get
			{	// Singleton
				if (_Current == null)
				{
					lock (_Locker)
					{
						if (_Current == null)
						{
							Repository repo = Repository.GetNew();
							_Current = repo;
						}
					}
				}
				return _Current;
			}
		}
		/// <summary>
		/// Privátní konstruktor (jde o singleton)
		/// </summary>
		private Repository() { }
		private static Repository GetNew()
		{
			Repository repo = new Repository();
			repo._PreLoadData();
			return repo;
		}
		/// <summary>
		/// Úložiště instance
		/// </summary>
		private static Repository _Current;
		/// <summary>
		/// Zámek při vytvoření instance
		/// </summary>
		private static Object _Locker = new Object();
		#endregion
		#region INSTANCE OBJEKTŮ, PRELOAD
		/// <summary>
		/// Přednačtení dat.
		/// Je vyvoláno bezpečně jen jedenkrát.
		/// </summary>
		private void _PreLoadData()
		{
			this._Classes = new ClassesCls(250);
			this._Tables = new DbTablesCls(300);
			this._Folders = new FoldersCls(350);
			this._Relations = new RelationsCls(1000);
			this._Filters = new FiltersCls(120);
			this._Templates = new TemplatesCls(60);
			this._EditStyles = new EditStylesCls(250);
		}
		private ClassesCls _Classes;
		private DbTablesCls _Tables;
		private FoldersCls _Folders;
		private RelationsCls _Relations;
		private FiltersCls _Filters;
		private TemplatesCls _Templates;
		private EditStylesCls _EditStyles;
		#endregion
		#region JEDNOTLIVÉ STATICKÉ PROPERTY PRO PŘÍSTUP K DATŮM REPOZITORY
		/// <summary>
		/// Repozitory tříd
		/// </summary>
		public static ClassesCls Classes { get { return Current._Classes; } }
		/// <summary>
		/// Repozitory všech tabulek v databázi. 
		/// Na každou tabulku se můžeme zeptat. Pokud tabulka v databázi neexistuje, vrátí se false.
		/// </summary>
		public static DbTablesCls Tables { get { return Current._Tables; } }
		/// <summary>
		/// Repozitory pořadačů
		/// </summary>
		public static FoldersCls Folders { get { return Current._Folders; } }
		/// <summary>
		/// Repozitory vztahů
		/// </summary>
		public static RelationsCls Relations { get { return Current._Relations; } }
		/// <summary>
		/// Repozitory filtrů
		/// </summary>
		public static FiltersCls Filters { get { return Current._Filters; } }
		/// <summary>
		/// Repozitory šablon
		/// </summary>
		public static TemplatesCls Templates { get { return Current._Templates; } }
		/// <summary>
		/// Editační styly
		/// </summary>
		public static EditStylesCls EditStyles { get { return Current._EditStyles; } }
		/// <summary>
		/// Metoda, která vyčistí veškerou repozitory.
		/// Typicky se použije při přepínání databázových profilů.
		/// </summary>
		public static void Reset()
		{
			Classes.Reset();
			Tables.Reset();
			Folders.Reset();
			Relations.Reset();
			Filters.Reset();
			Templates.Reset();
			EditStyles.Reset();
		}
		#endregion
	}
	#endregion
	#region CLASS ClassesCls a ClassInfo ( + NorisAttributesCls)
	/// <summary>
	/// Sada Noris datových tříd
	/// </summary>
	public class ClassesCls : RepositorySegmentCls<Int32, ClassInfo>
	{
		/// <summary>
		/// Konstruktor. Na vstupu očekává maximální počet záznamů, které může držet v paměti.
		/// Pokud by načítal další záznamy, pak nejstarší z paměti uvolní.
		/// </summary>
		/// <param name="maxItemCnt">Nejvyšší počet záznamů. -1 = neomezeně. 0 = žádný !!!</param>
		public ClassesCls(int maxItemCnt)
			: base(maxItemCnt)
		{ }
		/// <summary>
		/// Tato property vrátí SQL SELECT pro načtení jednoho záznamu s daty.
		/// SQL SELECT musí ve vhodném místě obsahovat token {{RecordNumber}}, na jehož místo jádro dosadí číslo hledaného záznamu nebo seznam čísel.
		/// Konkrétně, select by měl obsahovat frázi: "WHERE cislo_tridy {{RecordNumber}}", 
		/// jádro pak dosadí buď "WHERE cislo_tridy = 12345", 
		/// anebo dosadí "WHERE cislo_tridy in (1,2,3,4,5,6,7)", podle požadavku.
		/// Kdo nemá rád explicitní texty, určitě rád použije konstantu TOKEN_RECORD_NUMBER.
		/// </summary>
		protected override string SqlSelect
		{
			get
			{
				return ClassInfo.SqlSelect + " WHERE cislo_tridy " + TOKEN_RECORD_NUMBER;
			}
		}
		/// <summary>
		/// Háček volaný po načtení záznamu z databáze.
		/// Háček se volá i když je přepsaná virtuální metoda this.GetDataItem(), je volán před háčkem DataItemAddBefore() / DataItemValidateBefore()
		/// </summary>
		/// <param name="item"></param>
		protected override void DataItemRetrieveAfter(ClassInfo item)
		{
			base.DataItemRetrieveAfter(item);
		}
        /// <summary>
        /// Načte a vrátí položky odpovídající třídám dle daného filtru
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        protected override IEnumerable<RepositoryTextItem<int>> LoadAllTexts(string where)
        {
            string sql = "SELECT cislo_tridy as item_key, nazev_tridy as text FROM lcs.noris_classes" + (where == null ? "" : " WHERE " + where) + " ORDER BY nazev_tridy";
            DataConnector connector = GetRepositoryConnector();
            List<RepositoryTextItem<int>> list = Db_Layer.GetList<RepositoryTextItem<int>>(sql);
            return list;
        }
	}
	/// <summary>
	/// Informace o jedné Noris datové třídě
	/// </summary>
	public class ClassInfo : RepositorySegmentItem<Int32>, IDbRecord
	{
		#region Abstract and overrides
		/// <summary>
		/// Klíčová hodnota záznamu. Potomek musí implementovat = namapovat na konkrétní property, která nese skutečný klíč záznamu.
		/// </summary>
		protected override Int32 CurrentKeyValue { get { return this._cislo_tridy; } set { this._cislo_tridy = value; } }
		/// <summary>
		/// Číslo záznamu. Potomek musí implementovat = namapovat na konkrétní property, která nese skutečné číslo záznamu.
		/// </summary>
		// public override Int32 CurrentRecordNumber { get { return this._cislo_tridy; } protected set { this._cislo_tridy = value; } }
		/// <summary>
		/// Vizualizace
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			return "Class " + this.CisloTridy.ToString() + ": " + this.NazevTridy;
		}
		#endregion
		#region Public data property
		///<summary><para>Db: lcs.noris_classes.cislo_tridy (int not null)</para></summary>
		public int CisloTridy { get { return _cislo_tridy; } }
		///<summary><para>Db: lcs.noris_classes.nazev_tridy (varchar (40) null)</para></summary>
		public string NazevTridy { get { return _nazev_tridy; } }
		///<summary><para>Db: lcs.noris_classes.nazev_tabulky (varchar (40) null)</para></summary>
		public string NazevTabulky { get { return _nazev_tabulky.AllTrim(); } }
		///<summary><para>Db: lcs.noris_classes.priznak_ie (char (1) null)</para></summary>
		public string PriznakIe { get { return _priznak_ie; } }
		///<summary><para>Db: lcs.noris_classes.tabulka_objects (varchar (40) null)</para></summary>
		public string TabulkaObjects { get { return _tabulka_objects.AllTrim(); } }
		///<summary><para>Db: lcs.noris_classes.bmp_name (varchar (40) null)</para></summary>
		public string BmpName { get { return _bmp_name.AllTrim(); } }
		///<summary><para>Db: lcs.noris_classes.typ_tridy (char (1) null)</para></summary>
		public string TypTridy { get { return _typ_tridy.AllTrim(); } }
		///<summary><para>Db: lcs.noris_classes.kopirovat_sys_atr (char (1) null)</para></summary>
		public string KopirovatSysAtr { get { return _kopirovat_sys_atr.AllTrim(); } }
		///<summary><para>Db: lcs.noris_classes.trida_konfigu (int null)</para></summary>
		public SqlInt32 TridaKonfigu { get { return _trida_konfigu; } }
		///<summary><para>Db: lcs.noris_classes.enable_uda (char (1) null)</para></summary>
		public string EnableUda { get { return _enable_uda.AllTrim(); } }
		///<summary><para>Db: lcs.noris_classes.uda_table (varchar (50) null)</para></summary>
		public string UdaTable { get { return _uda_table.AllTrim(); } }
		///<summary><para>Db: lcs.noris_classes.enable_udapol (char (1) null)</para></summary>
		public string EnableUdapol { get { return _enable_udapol.AllTrim(); } }
		///<summary><para>Db: lcs.noris_classes.udapol_table (varchar (50) null)</para></summary>
		public string UdapolTable { get { return _udapol_table.AllTrim(); } }
		#endregion
		#region Protected data fields
		#pragma warning disable 1591
		protected int _cislo_tridy;
		protected string _nazev_tridy;
		protected string _nazev_tabulky;
		protected string _priznak_ie;
		protected string _tabulka_objects;
		protected string _bmp_name;
		protected string _typ_tridy;
		protected string _kopirovat_sys_atr;
		protected SqlInt32 _trida_konfigu;
		protected string _enable_uda;
		protected string _uda_table;
		protected string _enable_udapol;
		protected string _udapol_table;
		#pragma warning restore 1591
		#endregion
		#region IDbRecord
		int IDbRecord.RecordNumber { get; set; }
		/// <summary>
		/// Metoda, která umožní rychle naplnit záznam daty z přicházejícího datareaderu.
		/// Typové čtení zajišťuje mapa, metodou map.GetItem...(string columnName).
		/// Metoda má vracet true = data byla skutečně načtena a do záznamu uložena (false = nedošlo k tomu, data se budou načítat genericky).
		/// </summary>
		/// <param name="reader"></param>
		/// <param name="map"></param>
		/// <returns></returns>
		bool IDbFill.FillFromReader(SqlDataReader reader, FieldMapperLoad map)
		{
			_cislo_tridy = (int)map.FillDataIntoField<int>("cislo_tridy", reader);
			_nazev_tridy = (string)map.FillDataIntoField<string>("nazev_tridy", reader);
			_nazev_tabulky = (string)map.FillDataIntoField<string>("nazev_tabulky", reader);
			_priznak_ie = (string)map.FillDataIntoField<string>("priznak_ie", reader);
			_tabulka_objects = (string)map.FillDataIntoField<string>("tabulka_objects", reader);
			_bmp_name = (string)map.FillDataIntoField<string>("bmp_name", reader);
			_typ_tridy = (string)map.FillDataIntoField<string>("typ_tridy", reader);
			_kopirovat_sys_atr = (string)map.FillDataIntoField<string>("kopirovat_sys_atr", reader);
			_trida_konfigu = (SqlInt32)map.FillDataIntoField<SqlInt32>("trida_konfigu", reader);
			_enable_uda = (string)map.FillDataIntoField<string>("enable_uda", reader);
			_uda_table = (string)map.FillDataIntoField<string>("uda_table", reader);
			_enable_udapol = (string)map.FillDataIntoField<string>("enable_udapol", reader);
			_udapol_table = (string)map.FillDataIntoField<string>("udapol_table", reader);
			return true;
		}
		/// <summary>
		/// Metoda, ve které datový objekt připraví podklady pro uložení svých dat do databáze.
		/// Objekt svoje proměnné vloží do exportní mapy prostřednictvím metod map.AddTable(); map.AddColumn();
		/// Pokud objekt chce plnit více tabulek, plní je do mapy postupně, vždy v pořadí {tabulka, sloupce tabulky; další tabulka; sloupce}.
		/// Po naplnění mapy se vrací true.
		/// </summary>
		/// <param name="map"></param>
		/// <returns></returns>
		bool IDbRecord.PrepareSaveData(FieldMapperSave map) 
		{ return false; }
		#endregion
		#region Static generátor SQL selectu
		/// <summary>
		/// SQL SELECT pro načtení columnů, odpovídajících této struktuře. Pozor: neobsahuje filtr ani order.
		/// </summary>
		public static string SqlSelect { get { return @"SELECT cislo_tridy, nazev_tridy, nazev_tabulky, priznak_ie, tabulka_objects, bmp_name, typ_tridy, kopirovat_sys_atr, trida_konfigu, enable_uda, uda_table, enable_udapol, udapol_table FROM lcs.noris_classes"; } }
		#endregion
		#region Overrides
		/// <summary>
		/// Háček, který je zavolán po načtení dat.
		/// </summary>
		protected override void RetrieveAfter()
		{
			List<int> list = this._GetFolderNumberList();
		}
		#endregion
		#region Rozšíření o další data
		/// <summary>
		/// Seznam všech pořadačů této třídy.
		/// </summary>
		public List<FolderInfo> FolderList { get { return this._GetFolderInfoList(); } }
		/// <summary>
		/// První (= systémový) pořadač. Má nejmenší číslo. Vrací null, když neexistuje ani jeden. 
		/// </summary>
		public FolderInfo FolderSystem { get { return this._GetFolderSystem(); } }
		/// <summary>
		/// Seznam všech vztahů z této třídy (odtud zleva někam doprava).
		/// </summary>
		[Obsolete("Použijte property this.RelationLeftList.", true)]
        public List<RelationInfo> RelationList { get { return this._GetRelationLeftInfoList(); } }
        /// <summary>
        /// Seznam všech vztahů z této třídy (odtud zleva někam doprava).
        /// </summary>
        public List<RelationInfo> RelationLeftList { get { return this._GetRelationLeftInfoList(); } }
        /// <summary>
        /// Seznam všech vztahů z této třídy (odtud zleva někam doprava).
        /// Vrací instance třídy RelationSideInfo, v níž je uložená navíc i strana vztahu (zde je strana Right, protože vztah ukazuje doprava).
        /// </summary>
        public List<RelationSideInfo> RelationSideLeftList { get { return this._GetRelationSideLeftInfoList(); } }
        /// <summary>
        /// Seznam všech vztahů do některého z pořadačů této třídy (odkudsi zleva sem doprava).
        /// </summary>
        public List<RelationInfo> RelationTargetList { get { return this._GetRelationTargetInfoList(); } }
        /// <summary>
        /// Seznam všech vztahů do některého z pořadačů této třídy (odkudsi zleva sem doprava).
        /// Vrací instance třídy RelationSideInfo, v níž je uložená navíc i strana vztahu (zde je strana Left, protože vztah ukazuje doleva).
        /// </summary>
        public List<RelationSideInfo> RelationSideTargetList { get { return this._GetRelationSideTargetInfoList(); } }
        /// <summary>
		/// Seznam atributů této třídy
		/// </summary>
		public List<NorisAttributesCls> AttributesList { get { return this._GetAttributeList(); } }
		/// <summary>
		/// Najde a vrátí atribut daného plného jména (Dbname = plné jméno, včetně tabulky).
		/// </summary>
		/// <param name="dbName"></param>
		/// <returns></returns>
		public NorisAttributesCls FindAttribute(string dbName)
		{
			NorisAttributesCls attribute = this.AttributesList.FirstOrDefault(a => a.Dbname == dbName);
			return attribute;
		}
		/// <summary>
		/// Najde a vrátí atribut daného jména (Column = holé jméno, bez tabulky).
		/// Hledá atribut patřící do dané tabulky (podle typu tabulky).
		/// </summary>
		/// <param name="column">Holé jméno atributu bez tabulky, například "pocet"</param>
		/// <param name="tableType">Typ tabulky</param>
		/// <returns></returns>
		public NorisAttributesCls FindAttribute(string column, ClassTableType tableType)
		{
			NorisAttributesCls attribute = this.AttributesList.FirstOrDefault(a => a.Column == column && a.TableType == tableType);
			return attribute;
		}
		/// <summary>
		/// Najde a vrátí atribut daného jména (Column = holé jméno, bez tabulky).
		/// Hledá atribut hlavičkový / položkový podle parametru isEntry.
		/// </summary>
		/// <param name="column">Holé jméno atributu bez tabulky, například "pocet"</param>
		/// <param name="isEntry">Příznak, že se má hledat v položkách</param>
		/// <returns></returns>
		public NorisAttributesCls FindAttribute(string column, bool isEntry)
		{
			NorisAttributesCls attribute = this.AttributesList.FirstOrDefault(a => a.Column == column && a.IsEntry == isEntry);
			return attribute;
		}
        /// <summary>
        /// Najde a vrátí statický vztah daného plného jména (Dbname = plné jméno, včetně tabulky).
        /// </summary>
        /// <param name="dbName"></param>
        /// <returns></returns>
        public RelationInfo FindStaticRelation(string dbName)
        {
            RelationInfo relation = this.RelationLeftList.FirstOrDefault(r => r.RelationStatDyn == RelationStatDynType.Static && r.ColumnName == dbName);
            return relation;
        }
        /// <summary>
        /// Najde a vrátí statický vztah daného jména (Column = holé jméno, bez tabulky).
        /// Hledá vztah patřící do dané tabulky (podle typu tabulky).
        /// </summary>
        /// <param name="column">Holé jméno atributu bez tabulky, například "pocet"</param>
        /// <param name="tableType">Typ tabulky</param>
        /// <returns></returns>
        public RelationInfo FindStaticRelation(string column, ClassTableType tableType)
        {
            string tableName = this.GetTableName(tableType);
            RelationInfo relation = this.RelationLeftList.FirstOrDefault(r => r.RelationStatDyn == RelationStatDynType.Static && r.DbColumn == column && String.Equals(r.TableName, tableName, StringComparison.InvariantCultureIgnoreCase));
            return relation;
        }
        /// <summary>
        /// Najde a vrátí statický vztah daného jména (Column = holé jméno, bez tabulky).
        /// Hledá vztah hlavičkový / položkový podle parametru isEntry.
        /// </summary>
        /// <param name="column">Holé jméno atributu bez tabulky, například "pocet"</param>
        /// <param name="isEntry">Příznak, že se má hledat v položkách</param>
        /// <returns></returns>
        public RelationInfo FindStaticRelation(string column, bool isEntry)
        {
            RelationInfo relation = this.RelationLeftList.FirstOrDefault(r => r.RelationStatDyn == RelationStatDynType.Static && r.DbColumn == column && r.IsEntry == isEntry);
            return relation;
        }
		#region ON-DEMAND NAČÍTÁNÍ VÁZANÝCH ÚDAJŮ
		/// <summary>
		/// Úložiště seznamu čísel pořadačů této třídy
		/// </summary>
		private List<int> _FolderNumberList;
		private object _FnlLocker = new object();
		/// <summary>
		/// Úložiště seznamu čísel vztahů z této třídy (odtud zleva někam doprava)
		/// </summary>
		private List<int> _RelationLeftNumberList;
        /// <summary>
        /// Úložiště seznamu čísel vztahů do této třídy (odněkud zleva sem doprava)
        /// </summary>
        private List<int> _RelationTargetNumberList;
        private object _RLLocker = new object();
        private object _RRLocker = new object();
		/// <summary>
		/// Úložiště atributů této třídy, přímo jejich data
		/// </summary>
		private List<NorisAttributesCls> _AttributeList;
		private object _AdlLocker = new object();
		/// <summary>
		/// Vrátí seznam dat o pořadačích této třídy
		/// </summary>
		/// <returns></returns>
		private List<FolderInfo> _GetFolderInfoList()
		{
			List<int> list = this._GetFolderNumberList();
			return Repository.Folders.GetList(list);
		}
		/// <summary>
		/// Vrací systémový pořadač.
		/// </summary>
		/// <returns></returns>
		private FolderInfo _GetFolderSystem()
		{
			List<int> list = this._GetFolderNumberList();
			if (list.Count == 0) return null;
			return Repository.Folders[list[0]];
		}
		/// <summary>
        /// Vrátí seznam dat o vztazích této z třídy (odtud zleva někam doprava).
		/// </summary>
		/// <returns></returns>
		private List<RelationInfo> _GetRelationLeftInfoList()
		{
			List<int> list = this._GetRelationLeftNumberList();
			return Repository.Relations.GetList(list);
		}
        /// <summary>
        /// Vrátí seznam dat o vztazích této z třídy (odtud zleva někam doprava).
        /// Vrací instance třídy RelationSideInfo, v níž je uložená navíc i strana vztahu (zde je strana Right, protože vztah ukazuje doprava).
        /// </summary>
        /// <returns></returns>
        private List<RelationSideInfo> _GetRelationSideLeftInfoList()
        {
            List<int> list = this._GetRelationLeftNumberList();
            return Repository.Relations.GetSideList(list, RelationSideType.Right);
        }
        /// <summary>
        /// Vrátí seznam všech vztahů do některého z pořadačů této třídy (odkudsi zleva sem doprava).
		/// </summary>
		/// <returns></returns>
        private List<RelationInfo> _GetRelationTargetInfoList()
		{
			List<int> list = this._GetRelationTargetNumberList();
			return Repository.Relations.GetList(list);
		}
        /// <summary>
        /// Vrátí seznam všech vztahů do některého z pořadačů této třídy (odkudsi zleva sem doprava).
        /// Vrací instance třídy RelationSideInfo, v níž je uložená navíc i strana vztahu (zde je strana Left, protože vztah ukazuje doleva).
        /// </summary>
        /// <returns></returns>
        private List<RelationSideInfo> _GetRelationSideTargetInfoList()
        {
            List<int> list = this._GetRelationTargetNumberList();
            return Repository.Relations.GetSideList(list, RelationSideType.Left);
        }
        /// <summary>
		/// Vrátí seznam čísel pořadačů této třídy. Pokud je načten, vrátí jej z paměti. Pokud není načten, načte jej, uloží do paměti a vrátí.
		/// </summary>
		private List<int> _GetFolderNumberList()
		{
			List<int> result = this._FolderNumberList;
			if (result == null)
			{
				lock (this._FnlLocker)
				{
					if (this._FolderNumberList == null)
					{
						string sql = "SELECT cislo_poradace FROM lcs.poradace WHERE cislo_tridy = " + SqlFormat.ToSql(this.CisloTridy) + " ORDER BY cislo_poradace";
						result = Db_Layer.GetList<int>(sql, this.ExternalDataConnector);
						this._FolderNumberList = result;
					}
				}
			}
			return result;
		}
		/// <summary>
		/// Vrátí seznam čísel vztahů z této třídy (odtud zleva kamkoliv doprava).
        /// Pokud je načten, vrátí jej z paměti. Pokud není načten, načte jej, uloží do paměti a vrátí.
        /// Vrací pouze vztahy z třídy, nikoli vztahy z pořadačů této třídy.
        /// Vztahy z pořadačů lze načíst přes pořadače této třídy, a vztahy z pořadačů.
		/// </summary>
		private List<int> _GetRelationLeftNumberList()
		{
			List<int> result = this._RelationLeftNumberList;
			if (result == null)
			{
				lock (this._RLLocker)
				{
					if (this._RelationLeftNumberList == null)
					{
						string sql = "SELECT cislo_vztahu FROM lcs.vztahy WHERE cislo_tridy = " + SqlFormat.ToSql(this.CisloTridy) + " ORDER BY cislo_vztahu";
                        result = Db_Layer.GetList<int>(sql, this.ExternalDataConnector);
						this._RelationLeftNumberList = result;
					}
				}
			}
			return result;
		}
        /// <summary>
        /// Vrátí seznam čísel vztahů do kteréhokoli pořadače této třídy (odkudkoliv zleva sem doprava).
        /// Pokud je načten, vrátí jej z paměti. Pokud není načten, načte jej, uloží do paměti a vrátí.
        /// </summary>
        private List<int> _GetRelationTargetNumberList()
        {
            List<int> result = this._RelationTargetNumberList;
            if (result == null)
            {
                lock (this._RRLocker)
                {
                    if (this._RelationTargetNumberList == null)
                    {
                        string sql = "SELECT distinct cislo_vztahu FROM lcs.vztahporadac WHERE cislo_poradace in (select cislo_poradace from lcs.poradace where cislo_tridy = " + SqlFormat.ToSql(this.CisloTridy) + ") ORDER BY cislo_vztahu";
                        result = Db_Layer.GetList<int>(sql, this.ExternalDataConnector);
                        this._RelationTargetNumberList = result;
                    }
                }
            }
            return result;
        }
		/// <summary>
		/// Vrátí seznam atributů této třídy.
		/// Atributy nemají vlastní cache, jsou fyzicky umístěny ve své třídě (tj. zde), na rozdíl od vztahů a pořadačů.
		/// </summary>
		private List<NorisAttributesCls> _GetAttributeList()
		{
			if (this._AttributeList == null)
			{
				lock (this._AdlLocker)
				{
					if (this._AttributeList == null)
					{
						string sql = NorisAttributesCls.SqlSelect + " WHERE cislo_tridy = " + SqlFormat.ToSql(this.CisloTridy) + " ORDER BY poradi,cislo_atributu";
                        List<NorisAttributesCls> attList = Db_Layer.GetList<NorisAttributesCls>(sql, this.ExternalDataConnector);

                        // Takhle načtené atributy ještě nejsou kompletní: doplním do nich sebe = třídu jako ParentClass, a detekuji typ tabulky atributu podle jejího sloupce:
                        foreach (NorisAttributesCls attribute in attList)
                            attribute.Initialize(this);

                        this._AttributeList = attList;
					}
				}
			}
			return this._AttributeList;
		}
		#endregion
        #region URČENÍ ATRIBUTU
        /// <summary>
        /// Určí, do které tabulky daný atribut patří
        /// </summary>
        /// <param name="norisAttributes">Data o atributu</param>
        /// <returns></returns>
        public ClassTableType DetectTableType(NorisAttributesCls norisAttributes)
        {
            return DetectTableType(norisAttributes.Dbname);
        }
		/// <summary>
		/// Určí, do které tabulky daný vztah patří
		/// </summary>
		/// <param name="relationInfo">Data o vztahu</param>
		/// <returns></returns>
		public ClassTableType DetectRelationTable(RelationInfo relationInfo)
		{
			return DetectTableType(relationInfo.ColumnName);
		}
		/// <summary>
        /// Určí, do které tabulky daný atribut patří
        /// </summary>
		/// <param name="dbColumnFullName">Název databázového sloupce (fullname: "lcs.subjekty.pachatel")</param>
        /// <returns></returns>
        internal ClassTableType DetectTableType(string dbColumnFullName)
        {
            string dbName = dbColumnFullName.Trim().ToLower();
            if (this.IsSubject && dbName.StartsWith("lcs.subjekty.", StringComparison.OrdinalIgnoreCase)) return ClassTableType.Subjekt;
            if (!String.IsNullOrEmpty(this.NazevTabulky) && dbName.StartsWith("lcs." + this.NazevTabulky.Trim() + ".", StringComparison.OrdinalIgnoreCase)) return ClassTableType.Master;
            if (this.HasEntries && dbName.StartsWith("lcs." + this.TabulkaObjects.Trim() + ".", StringComparison.OrdinalIgnoreCase)) return ClassTableType.Entries;
            if (this.HasUdaMaster && dbName.StartsWith("lcs." + this.UdaTable.Trim() + ".", StringComparison.OrdinalIgnoreCase)) return ClassTableType.UdaMaster;
            if (this.HasUdaEntries && dbName.StartsWith("lcs." + this.UdapolTable.Trim() + ".", StringComparison.OrdinalIgnoreCase)) return ClassTableType.UdaEntries;
            return ClassTableType.None;
        }
        #endregion
        #endregion
        #region DRUH TŘÍDY, TYPOVÝ PŘÍSTUP K NÁZVŮM TABULEK
        /// <summary>
		/// Je tato třída subjektová?
		/// (Položkovou třídu lze ověřit pomocí property IsEntries)
		/// </summary>
		public bool IsSubject
		{ get { return String.Equals(this.TypTridy, "S"); } }
		/// <summary>
		/// Je tato třída položková?
		/// Položková třída má nastaveno Subjektová (IsSubject) a má vyplněnou tabulku objektů (TabulkaObjects)
		/// </summary>
		public bool IsEntries
		{ get { return this.IsSubject && this.HasEntries; } }
		/// <summary>
		/// Má tato třída položky? (Pouze vyplněnost atributu TabulkaObjects).
		/// </summary>
		public bool HasEntries
		{ get { return !this.TabulkaObjects.IsEmpty(); } }
		/// <summary>
		/// Má tato třída UD atributy Master?
		/// </summary>
		public bool HasUdaMaster
		{ get { return String.Equals(this.EnableUda, "A") && !this.UdaTable.IsEmpty(); } }
		/// <summary>
		/// Má tato třída UD atributy Entries?
		/// </summary>
		public bool HasUdaEntries
		{ get { return this.HasEntries && String.Equals(this.EnableUdapol, "A") && !this.UdapolTable.IsEmpty(); } }
        /// <summary>
        /// Příznak, že tato třída má na záznamech explicitně určené číslo pořadače.
        /// Subjektové vždy, nonsubjektové tehdy pokud mají v Master tabulce sloupec "cislo_poradace (int)".
        /// </summary>
        public bool HasFolders
        {
            get
            {
                if (!this._HasFolders.HasValue)
                {
                    // Subjektové jsou vždy ANO:
                    bool hasFolder = this.IsSubject;
                    if (!hasFolder)
                    {   // Nonsubjektové třídy:
                        string tableName = this.GetTableName(ClassTableType.Master);
                        DbTableInfo masterTable;
                        if (Repository.Tables.TryGetValue(tableName, out masterTable))
                        {
                            DbColumnInfo columnPoradac;
                            if (masterTable.TryFindColumn("cislo_poradace", out columnPoradac))
                                hasFolder = (columnPoradac.TypeName == "int");
                        }
                    }
                    this._HasFolders = hasFolder;
                }
                return this._HasFolders.Value;
            }
        }
        private bool? _HasFolders = null;
		/// <summary>
		/// Typ tabulky, která je master do selectů (pro nonsubjektové třídy je to Master, pro subjektové Subjekt)
		/// </summary>
		public ClassTableType MasterTableType { get { return (this.IsSubject ? ClassTableType.Subjekt : ClassTableType.Master); } }
		/// <summary>
		/// Vrátí jméno tabulky pro daný účel. Pokud třída nepotřebuje pro daný účel tabulku, vrací null.
		/// Vrácené jméno tabulky má vždy svého vlastníka (před tabulku Master a Entries doplním lcs., před uda nedoplňuji - ty jsou s vlastníkem už načteny)
		/// Vrácený název je vždy lowercase.
        /// Tato varianta akceptuje název sloupce tableColumn, a rozhoduje se zda použít master tabulku subjektových tříd nebo tabulku subjektů.
		/// </summary>
		/// <param name="tableType">Typ tabulky</param>
        /// <param name="tableColumn">Název db sloupce. Pro typ tabulky Subjekt a Master detekuje, v které tabulce se sloupec nachází.</param>
		/// <returns></returns>
        public string GetTableName(ClassTableType tableType, string tableColumn)
        {
            if (tableType == ClassTableType.Subjekt || tableType == ClassTableType.Master)
            {
                bool containColumn = false;
                // Necháme si určit tabulku - bez zohlednění názvu sloupce (je to rychlé, jde jen o jeden switch):
                string tableName = this.GetTableName(tableType);
				string columnName = tableColumn.Trim().ToLower();
                DbTableInfo tablesInfo;
				if (Repository.Tables.TryGetValue(tableName, out tablesInfo))
					containColumn = tablesInfo.ContainColumn(columnName);
				if (!containColumn)
				{
					tableType = (tableType == ClassTableType.Subjekt ? ClassTableType.Master : ClassTableType.Subjekt);
					tableName = this.GetTableName(tableType);
					if (Repository.Tables.TryGetValue(tableName, out tablesInfo))
						containColumn = tablesInfo.ColumnList.Any(c => c.ColumnName == columnName);
				}
				if (containColumn) return tableName;
            }
            return this.GetTableName(tableType);
        }
        /// <summary>
        /// Vrátí true, pokud tato třída používá tabulku daného typu.
        /// </summary>
        /// <param name="tableType"></param>
        /// <returns></returns>
        public bool ContainTable(ClassTableType tableType)
        {
            string tableName = this.GetTableName(tableType);
            return (tableName != null);
        }
		/// <summary>
        /// Vrátí true, pokud tato třída používá tabulku daného jména.
        /// </summary>
        /// <param name="tableType"></param>
        /// <returns></returns>
        public bool ContainTable(string tableName)
        {
            return (this.GetTableType(tableName) != ClassTableType.None);
        }
		/// <summary>
		/// Vrátí jméno tabulky pro daný účel. Pokud třída nepotřebuje pro daný účel tabulku, vrací null.
		/// Vrácené jméno tabulky má vždy svého vlastníka (před tabulku Master a Entries doplním lcs., před uda nedoplňuji - ty jsou s vlastníkem už načteny)
		/// Vrácený název je vždy lowercase.
		/// </summary>
		/// <param name="tableType">Typ tabulky</param>
		/// <returns></returns>
		public string GetTableName(ClassTableType tableType)
		{
			switch (tableType)
			{
				case ClassTableType.Subjekt:
					return (this.IsSubject ? "lcs.subjekty" : null);
				case ClassTableType.Master:
					return "lcs." + this.NazevTabulky.ToLower();
				case ClassTableType.Entries:
					return (this.HasEntries ? "lcs." + this.TabulkaObjects.ToLower() : null);
				case ClassTableType.UdaMaster:
					return (this.HasUdaMaster ? this.UdaTable.ToLower() : null);
				case ClassTableType.UdaEntries:
					return (this.HasUdaEntries ? this.UdapolTable.ToLower() : null);
			}
			return null;
		}
        /// <summary>
        /// Vrátí typ tabulky podle jejího jména.
        /// </summary>
        /// <param name="tableName"></param>
        /// <returns></returns>
        public ClassTableType GetTableType(string tableName)
        {
            if (String.IsNullOrEmpty(tableName)) return ClassTableType.None;
            string name = tableName.Trim().ToLower();
            if (String.Equals(name, this.GetTableName(ClassTableType.Subjekt), StringComparison.InvariantCultureIgnoreCase)) return ClassTableType.Subjekt;
            if (String.Equals(name, this.GetTableName(ClassTableType.Master), StringComparison.InvariantCultureIgnoreCase)) return ClassTableType.Master;
            if (String.Equals(name, this.GetTableName(ClassTableType.Entries), StringComparison.InvariantCultureIgnoreCase)) return ClassTableType.Entries;
            if (String.Equals(name, this.GetTableName(ClassTableType.UdaMaster), StringComparison.InvariantCultureIgnoreCase)) return ClassTableType.UdaMaster;
            if (String.Equals(name, this.GetTableName(ClassTableType.UdaEntries), StringComparison.InvariantCultureIgnoreCase)) return ClassTableType.UdaEntries;
            return ClassTableType.None;
        }
		/// <summary>
        /// Rozdělí full db column (typicky "lcs.product_order.status")
        /// na typ tabulky (zde to bude ClassTableType.Master) a na sloupec (zde "status").
        /// Vrací true, pokud je vše OK (=je detekována tabulka, která patří ke zdejší třídě, a sloupec je vyplněný = netestuje se jeho existence v tabulce).
        /// </summary>
        /// <param name="fullColumnName"></param>
        /// <param name="tableType"></param>
        /// <param name="dbColumn"></param>
        /// <returns></returns>
        public bool TryParseFullDbColumn(string fullColumnName, out ClassTableType tableType, out string dbColumn)
        {
            tableType = ClassTableType.None;
            dbColumn = null;

            string tableName;
            string columnName;
            if (!DbTableInfo.SplitFullDbColumn(fullColumnName, out tableName, out columnName)) return false;
            if (String.IsNullOrEmpty(columnName)) return false;

            ClassTableType type = this.GetTableType(tableName);
            if (type == ClassTableType.None) return false;

            tableType = type;
            dbColumn = columnName;
            return true;
        }
		/// <summary>
		/// Obsahuje název identity sloupce této třídy, master tabulka. Jde o "cislo_subjektu" nebo "cislo_nonsubjektu".
		/// </summary>
		public string MasterIdentityColumn { get { return GetIdentityColumn(ClassTableType.Master); } }
        /// <summary>
        /// Obsahuje název identity sloupce této třídy, entries tabulka. Jde o "cislo_objektu" nebo jiné (podle identity sloupce tabulky položek), nebo null.
        /// </summary>
        public string EntriesIdentityColumn { get { return GetIdentityColumn(ClassTableType.Entries); } }
        /// <summary>
        /// Vrátí reálný identity column pro požadovaný druh tabulky.
        /// Pro subjektové třídy pro tabulky třídy Subjekt a Master vrací "cislo_subjektu".
        /// Pro nonsubjektové třídy pro požadavek třídy Subjekt vrací null, 
        /// pro požadavek třídy Master vrací fyzický db identity sloupec konkrétní tabulky.
        /// Pro požadavek třídy Entries, UdaMaster a UdaEntries vrací fyzický db identity sloupec konkrétní tabulky,
        /// anebo pokud tabulka není definovaná tak null.
        /// Pokud tato třída danou tabulku nemá, vrací null.
        /// Pokud tabulku má, vrátí její Identity column, a to i pro tabulky, které jej fyzicky nemají = Master tabulky subjektových tříd !!!
        /// </summary>
        /// <param name="tableType">Typ tabulky, na kterou se ptáme. Informace o konkrétní tabulce jsou uloženy v datech této třídy.</param>
        /// <returns></returns>
        public string GetIdentityColumn(ClassTableType tableType)
        {
            switch (tableType)
            {
                case ClassTableType.Subjekt:
                    return (this.IsSubject ? "cislo_subjektu" : null);
                case ClassTableType.Master:
                    if (this.IsSubject)
                        return "cislo_subjektu";
                    return GetIdentityColumn(this.NazevTabulky);
                case ClassTableType.Entries:
                    if (!this.HasEntries) return null;
                    return GetIdentityColumn(this.TabulkaObjects);
                case ClassTableType.UdaMaster:
                    if (!this.HasUdaMaster) return null;
                    return GetIdentityColumn(ClassTableType.Master);
                case ClassTableType.UdaEntries:
                    if (!this.HasUdaEntries) return null;
                    return GetIdentityColumn(ClassTableType.Entries);
            }
            return null;
        }
        /// <summary>
		/// Vrátí teoretický identity column pro požadovaný druh tabulky.
		/// Tj. vrací "cislo_subjektu", "cislo_nonsubjektu", "cislo_objektu", podle třídy.
		/// Orientuje se podle požadavku, typu třídy a přítomnosti tabulek (Entries, Uda).
		/// Nezjišťuje fyzický DB identity column.
		/// </summary>
		/// <param name="tableType">Typ tabulky, na kterou se ptáme. Informace o konkrétní tabulce jsou uloženy v datech této třídy.</param>
		/// <returns></returns>
		public string GetDefaultIdentityColumn(ClassTableType tableType)
		{
			switch (tableType)
			{
				case ClassTableType.Subjekt:
					return (this.IsSubject ? "cislo_subjektu" : null);
				case ClassTableType.Master:
					return (this.IsSubject ? "cislo_subjektu" : "cislo_nonsubjektu");
				case ClassTableType.Entries:
					if (!this.HasEntries) return null;
					return "cislo_objektu";
				case ClassTableType.UdaMaster:
					if (!this.HasUdaMaster) return null;
					return (this.IsSubject ? "cislo_subjektu" : "cislo_nonsubjektu");
				case ClassTableType.UdaEntries:
					if (!this.HasUdaEntries) return null;
					return "cislo_objektu";
			}
			return null;
		}
		/// <summary>
		/// Vrátí identity column pro požadovanou tabulku.
		/// Pokud daná tabulka nemá identity column, vrací "".
		/// Pokud tabulka neexistuje nebo není zadána, vrací null.
		/// </summary>
		/// <param name="tableName">Název tabulky, na kterou se ptáme.</param>
		/// <returns></returns>
		public static string GetIdentityColumn(string tableName)
		{
			if (String.IsNullOrEmpty(tableName)) return null;
			string table = tableName.Trim().ToLower();
			if (!table.Contains("."))
				table = "lcs." + table;

			DbTableInfo tableInfo = Repository.Tables[table];
			if (tableInfo == null) return null;                // Pokud tabulka neexistuje, vrací se null.
			string identityColumn = tableInfo.IdentityColumn;
			if (identityColumn == null) return "";             // Pokud tabulka nemá Identity column, vrací se "" a ne null!
			return identityColumn;
		}
        /// <summary>
        /// Metoda vrátí data tabulky daného typu pro tuto třídu.
        /// </summary>
        /// <param name="tableType"></param>
        /// <returns></returns>
        public DbTableInfo GetTable(ClassTableType tableType)
        {
            string tableName = this.GetTableName(tableType);
            if (String.IsNullOrEmpty(tableName)) return null;
            return Repository.Tables[tableName];
        }
        #endregion
		#region KONVERZE ENUMŮ TYPICKÝCH PRO TŘÍDU
		/// <summary>
		/// Vrátí jedno písmeno podle typu tabulky (S,M,E,U,P)
		/// </summary>
		/// <param name="tableType"></param>
		/// <returns></returns>
		public static string ConvertTableTypeToString(ClassTableType tableType)
		{
			switch (tableType)
			{
				case ClassTableType.Subjekt: return "S";
				case ClassTableType.Master: return "M";
				case ClassTableType.Entries: return "E";
				case ClassTableType.UdaMaster: return "U";
				case ClassTableType.UdaEntries: return "p";
			}
			return "";
		}
		#endregion
        #region KOMPARÁTORY
        /// <summary>
        /// Porovná dva záznamy dle čísla (Name)
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static int CompareByNumber(ClassInfo a, ClassInfo b)
        {
            if (a == null && b == null) return 0;
            if (a == null) return -1;
            if (b == null) return 1;
            return a.CisloTridy.CompareTo(b.CisloTridy);
        }
        /// <summary>
        /// Porovná dva záznamy dle názvu (NazevTridy)
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static int CompareByName(ClassInfo a, ClassInfo b)
        {
            if (a == null && b == null) return 0;
            if (a == null) return -1;
            if (b == null) return 1;
            return String.Compare(a.NazevTridy, b.NazevTridy);
        }
        #endregion
    }
	#region CLASS NorisAttributesCls : Třída odvozená z tabulky lcs.nis_columns
	/// <summary>
	/// NorisAttributesCls : Tato tabulka (lcs.nis_columns, původně noris_attributes) není navázaná k žádné Noris třídě.
	/// Data načtena z tabulky lcs.nis_columns (původně noris_attributes).
	/// </summary>
	public partial class NorisAttributesCls : Noris.Schedule.Support.Sql.IDbRecord
	{
		#region OVERRIDES
		/// <summary>
		/// Vizualizace
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			return "Attribute " + this.NazevCol + " (db: " + this.Dbname + ")";
		}
		#endregion
		#region Public systém property
		/// <summary>Číslo záznamu = </summary>
		public int RecordNumber { get { return this._cislo_tridy; } }
		#endregion
		#region Public data property
		///<summary><para>Db: lcs.noris_attributes.cislo_atributu (int not null)</para></summary>
		public int CisloAtributu { get { return _cislo_atributu; } }
		///<summary><para>Db: lcs.noris_attributes.cislo_tridy (int not null)</para></summary>
		public int CisloTridy { get { return _cislo_tridy; } }
		///<summary><para>Db: lcs.nis_columns.nazev_col (varchar (40) null)</para></summary>
		public string NazevCol { get { return _nazev_col; } }
		///<summary><para>Db: lcs.noris_attributes.dbname (varchar (70) not null)</para></summary>
		public string Dbname { get { return _dbname; } }
		///<summary><para>Db: lcs.noris_attributes.typ (varchar (40) not null)</para></summary>
		public string Typ { get { return _typ; } }
		///<summary><para>Db: lcs.noris_attributes.poradi (smallint null)</para></summary>
		public SqlInt16 Poradi { get { return _poradi; } }
		///<summary><para>Db: lcs.noris_attributes.expression (varchar (1500) null)</para></summary>
		public string Expression { get { return _expression; } }
		///<summary><para>Db: lcs.noris_attributes.editacni_styl (varchar (50) null)</para></summary>
		public string EditacniStyl { get { return _editacni_styl; } }
		///<summary><para>Db: lcs.noris_attributes.replikovat (varchar (1) null)</para></summary>
		public string Replikovat { get { return _replikovat; } }
		///<summary><para>Db: lcs.noris_attributes.zakaz_hz (varchar (1) null)</para></summary>
		public string ZakazHz { get { return _zakaz_hz; } }
		///<summary><para>Db: lcs.noris_attributes.povinna (char (1) null)</para></summary>
		public string Povinna { get { return _povinna; } }
		///<summary><para>Db: lcs.noris_attributes.nutnost_zadani (char (1) not null)</para></summary>
		public string NutnostZadani { get { return _nutnost_zadani; } }
		///<summary><para>Db: lcs.noris_attributes.is_nazev (char (1) not null)</para></summary>
		public string IsNazev { get { return _is_nazev; } }
		///<summary><para>Db: lcs.noris_attributes.is_refer (char (1) not null)</para></summary>
		public string IsRefer { get { return _is_refer; } }
		///<summary><para>Db: lcs.noris_attributes.zakazat_def (char (1) not null)</para></summary>
		public string ZakazatDef { get { return _zakazat_def; } }
		///<summary><para>Db: lcs.noris_attributes.primary_key_hint (char (1) null)</para></summary>
		public string PrimaryKeyHint { get { return _primary_key_hint; } }
		///<summary><para>Db: lcs.noris_attributes.priznak_castka_tuz_mena (char (1) null)</para></summary>
		public string PriznakCastkaTuzMena { get { return _priznak_castka_tuz_mena; } }
		#endregion
		#region Protected data fields
		#pragma warning disable 1591
		protected int _cislo_atributu;
		protected int _cislo_tridy;
		protected string _nazev_col;
		protected string _dbname;
		protected string _typ;
		protected SqlInt16 _poradi;
		protected string _expression;
		protected string _editacni_styl;
		protected string _replikovat;
		protected string _zakaz_hz;
		protected string _povinna;
		protected string _nutnost_zadani;
		protected string _is_nazev;
		protected string _is_refer;
		protected string _zakazat_def;
		protected string _primary_key_hint;
		protected string _priznak_castka_tuz_mena;
		#pragma warning restore 1591
		#endregion
		#region IDbRecord
		int IDbRecord.RecordNumber { get; set; }
		/// <summary>
		/// Metoda, která umožní rychle naplnit záznam daty z přicházejícího datareaderu.
		/// Typové čtení zajišťuje mapa, metodou map.GetItem...(string columnName).
		/// Metoda má vracet true = data byla skutečně načtena a do záznamu uložena (false = nedošlo k tomu, data se budou načítat genericky).
		/// </summary>
		/// <param name="reader"></param>
		/// <param name="map"></param>
		/// <returns></returns>
		bool IDbFill.FillFromReader(SqlDataReader reader, FieldMapperLoad map)
		{
			_cislo_atributu = (int)map.FillDataIntoField<int>("cislo_atributu", reader);
			_cislo_tridy = (int)map.FillDataIntoField<int>("cislo_tridy", reader);
			_nazev_col = (string)map.FillDataIntoField<string>("nazev_col", reader);
			_dbname = (string)map.FillDataIntoField<string>("dbname", reader);
			_typ = (string)map.FillDataIntoField<string>("typ", reader);
			_poradi = (SqlInt16)map.FillDataIntoField<SqlInt16>("poradi", reader);
			_expression = (string)map.FillDataIntoField<string>("expression", reader);
			_editacni_styl = (string)map.FillDataIntoField<string>("editacni_styl", reader);
			_replikovat = (string)map.FillDataIntoField<string>("replikovat", reader);
			_zakaz_hz = (string)map.FillDataIntoField<string>("zakaz_hz", reader);
			_povinna = (string)map.FillDataIntoField<string>("povinna", reader);
			_nutnost_zadani = (string)map.FillDataIntoField<string>("nutnost_zadani", reader);
			_is_nazev = (string)map.FillDataIntoField<string>("is_nazev", reader);
			_is_refer = (string)map.FillDataIntoField<string>("is_refer", reader);
			_zakazat_def = (string)map.FillDataIntoField<string>("zakazat_def", reader);
			_primary_key_hint = (string)map.FillDataIntoField<string>("primary_key_hint", reader);
			_priznak_castka_tuz_mena = (string)map.FillDataIntoField<string>("priznak_castka_tuz_mena", reader);
			// _sync_id = (string)map.FillDataIntoField<string>("sync_id", reader);
			return true;
		}
		/// <summary>
		/// Metoda, ve které datový objekt připraví podklady pro uložení svých dat do databáze.
		/// Objekt svoje proměnné vloží do exportní mapy prostřednictvím metod map.AddTable(); map.AddColumn();
		/// Pokud objekt chce plnit více tabulek, plní je do mapy postupně, vždy v pořadí {tabulka, sloupce tabulky; další tabulka; sloupce}.
		/// Po naplnění mapy se vrací true.
		/// </summary>
		/// <param name="map"></param>
		/// <returns></returns>
		bool IDbRecord.PrepareSaveData(FieldMapperSave map)
		{ return false; }
		#endregion
		#region Static generátor SQL selectu
		/// <summary>
		/// SQL SELECT pro načtení columnů, odpovídajících této struktuře. Pozor: neobsahuje filtr ani order.
		/// </summary>
		public static string SqlSelect { get { return @"SELECT cislo_atributu, cislo_tridy, nazev_col, dbname, typ, poradi, expression, editacni_styl, replikovat, zakaz_hz, povinna, nutnost_zadani, is_refer, is_nazev, zakazat_def, primary_key_hint, priznak_castka_tuz_mena, sync_id FROM lcs.nis_columns"; } }
		#endregion
        #region Rozšířené vlastnosti, inicializace po načtení z databáze
        /// <summary>
        /// Reference na třídu, do které patří tento atribut.
        /// Pokud je null, pak jde o neinicializovaný atribut, a takový by se neměl nikde vyskytovat.
        /// </summary>
        public ClassInfo ParentClass
        {
            get
            {
                if (this._ParentClass != null && this._ParentClass.IsAlive && this._ParentClass.Target is ClassInfo)
                    return this._ParentClass.Target as ClassInfo;
                return null;
            }
        }
        /// <summary>
        /// Typ tabulky, do které se ukládá tento atribut.
        /// </summary>
        public ClassTableType TableType { get; private set; }
        /// <summary>
        /// Holý databázový sloupec, bez prefixu (bez tabulky), například "pocet_polozek"
        /// </summary>
        public string Column { get; private set; }
		/// <summary>
        /// Je tento atribut vypočítaný? 
        /// Tzn. nebude existovat v databázi pod svým názvem, ale musí se z databáze "vypočítat".
        /// Výraz (this.Expression) se odkazuje na databázové sloupce s plným názvem své tabulky.
        /// </summary>
        public bool IsExpression { get { return (!String.IsNullOrEmpty(this.Expression)); } }
		/// <summary>
		/// Je tento atribut položkový?
		/// </summary>
		public bool IsEntry { get; private set; }
        /// <summary>
        /// Tabulka včetně vlastníka, například "lcs.organizace"
        /// </summary>
        public string TableName { get; private set; }
		/// <summary>
		/// Příznak, že tento atribut má editační styl.
        /// true = pokud název editačního stylu není empty.
        /// Získání této hodnoty neprovádí načtení obsahu editačního stylu, to provádí až čtení property this.EditStyle.
		/// </summary>
		public bool HasEditStyle { get { return (!String.IsNullOrEmpty(this.EditacniStyl)); } }
		/// <summary>
		/// Editační styl, on demand dotažený z repozitory editačních stylů.
		/// Může být null, pokud atribut nemá editační styl (HasEditStyle == false), nebo není nalezen.
        /// Editační styl se v atributu fyzicky neukládá, vždy se nově načítá z repozitory editačních stylů.
		/// </summary>
		public EditStyleInfo EditStyle
		{
			get
			{
				if (!this.HasEditStyle) return null;
				EditStyleInfo edStyle;
				if (!Repository.EditStyles.TryGetValue(this.EditacniStyl, out edStyle)) return null;
				return edStyle;
			}
		}
        /// <summary>
        /// Metoda vezme výraz this.Expression (pokud existuje), najde v něm názvy tabulek a vymění je za alias tabulek.
        /// Názvy tabulek vyhledává v proměnných ve výrazu (ignoruje obsah stringů a komentářů).
        /// Pokud proměnná obsahuje alespoň jednu tečku, považuje ji za db column, vyčlení z ní část před poslední tečkou a tu nahradí za alias.
        /// Nahrazování provádí metoda předaná jako parametr.
        /// Jde o funkci, která má na vstupu string (aktuální tabulka), a na výstupu očekáváme alias.
        /// Pokud bude na výstupu funkce null, pak se nahrazení neprovede.
        /// Pokud bude na výstupu funkce empty string, pak se tabulka z výrazu zcela odebere (i s tečkou).
        /// </summary>
        /// <param name="aliasGenerator">Metoda, která vyhledá alias pro danou tabulku.</param>
        /// <returns></returns>
        public string ExpressionAliased(Func<string, string> aliasGenerator)
        {
            if (String.IsNullOrEmpty(this.Expression))
                return this.Expression;
            return Parser.Parser.ChangeTableNameInExpression(this.Expression, aliasGenerator);
        }
        /// <summary>
        /// Provede inicializaci tohoto záznamu po jeho načtení z databáze.
        /// Doplní referenci na parent class, rozdělí this.Dbname do TableName a Column.
        /// Nelze volat více než 1x.
        /// </summary>
        /// <param name="parentClass"></param>
        internal void Initialize(ClassInfo parentClass)
        {
            if (parentClass == null) return;
            if (this.ParentClass != null)
                Throw.SysError(MessageInfo.Get("Došlo k pokusu o duplicitní inicializaci Noris atributu %0", this.NazevCol));

            this._ParentClass = new WeakReference(parentClass);
            this.TableType = parentClass.DetectTableType(this.Dbname);

            string[] dbItems = this.Dbname.Split('.');
            int colIdx = dbItems.Length - 1;
            string tableName = "";
            string column = "";
            for (int i = 0; i <= colIdx; i++)
            {
                if (i < colIdx)
                    tableName += (tableName.Length == 0 ? "" : ".") + dbItems[i];
                else
                    column = dbItems[i];
            }
            this.TableName = tableName;
            this.Column = column;
			this.IsEntry = (this.TableType == ClassTableType.Entries || this.TableType == ClassTableType.UdaEntries);
        }
        /// <summary>
        /// Soukromá WeakReference na ParentClass
        /// </summary>
        private WeakReference _ParentClass;
        #endregion
        #region Komparátory
        /// <summary>
        /// Porovná dva záznamy atributů pro jejich setřídění.
        /// Nejprve budou atributy dle typu tabulky (Subjekt - Master - UDA Master - Entries - UDA Entries),
        /// a v každé skupině budou dle tříděny jejich textového (uživatelského) názvu.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static int CompareByTypeName(NorisAttributesCls a, NorisAttributesCls b)
        {
            if (a == null && b == null) return 0;
            if (a == null) return -1;
            if (b == null) return 1;

            int cmp = ((int)a.TableType).CompareTo((int)b.TableType);
            if (cmp != 0) return cmp;

            return String.Compare(a.NazevCol, b.NazevCol, StringComparison.CurrentCultureIgnoreCase);
        }
        #endregion
    }
	#endregion
	/// <summary>
	/// Druh tabulky, podle použití v rámci Noris instance
	/// </summary>
	public enum ClassTableType
	{
        /// <summary>
        /// Žádný / neurčitelný typ
        /// </summary>
        None = 0,
		/// <summary>
		/// Tabulka lcs.subjekty
		/// </summary>
		Subjekt = 1,
		/// <summary>
		/// Master tabulka standardních sloupců (data záznamu / hlavičky)
		/// </summary>
		Master = 2,
		/// <summary>
		/// UDA tabulka sloupců (data záznamu / hlavičky, definovaná uživatelem)
		/// </summary>
		UdaMaster = 3,
        /// <summary>
        /// Entries tabulka standardních sloupců (položky)
        /// </summary>
        Entries = 4,
        /// <summary>
		/// UDA tabulka sloupců položek, definovaná uživatelem
		/// </summary>
		UdaEntries = 5
	}
	#endregion
    #region CLASS DbTablesCls, DbTableInfo a DbColumnInfo, enum DbObjectType
    /// <summary>
	/// Repozitory tabulek z připojené databáze (z SQL serveru)
	/// </summary>
	public class DbTablesCls : RepositorySegmentCls<String, DbTableInfo>
	{
		/// <summary>
		/// Konstruktor. Na vstupu očekává maximální počet záznamů, které může držet v paměti.
		/// Pokud by načítal další záznamy, pak nejstarší z paměti uvolní.
		/// </summary>
		/// <param name="maxItemCnt">Nejvyšší počet záznamů. -1 = neomezeně. 0 = žádný !!!</param>
		public DbTablesCls(int maxItemCnt)
			: base(maxItemCnt)
		{ }
		/// <summary>
		/// Tato property vrátí SQL SELECT pro načtení jednoho záznamu s daty.
		/// SQL SELECT musí ve vhodném místě obsahovat token {{RecordNumber}}, na jehož místo jádro dosadí číslo hledaného záznamu nebo seznam čísel.
		/// Konkrétně, select by měl obsahovat frázi: "WHERE cislo_tridy {{RecordNumber}}", 
		/// jádro pak dosadí buď "WHERE cislo_tridy = 12345", 
		/// anebo dosadí "WHERE cislo_tridy in (1,2,3,4,5,6,7)", podle požadavku.
		/// Kdo nemá rád explicitní texty, určitě rád použije konstantu TOKEN_RECORD_NUMBER.
		/// </summary>
		protected override string SqlSelect
		{
			get
			{
				return DbTableInfo.SqlSelect + " and (sch.name + '.' + obj.name) " + TOKEN_RECORD_NUMBER;
			}
		}
		/// <summary>
		/// Háček volaný po načtení záznamu z databáze.
		/// Háček se volá i když je přepsaná virtuální metoda this.GetDataItem(), je volán před háčkem DataItemAddBefore() / DataItemValidateBefore()
		/// </summary>
		/// <param name="item"></param>
		protected override void DataItemRetrieveAfter(DbTableInfo item)
		{
			base.DataItemRetrieveAfter(item);
		}
	}
	/// <summary>
	/// Informace o jedné tabulce / view v databázi
	/// </summary>
	public class DbTableInfo : RepositorySegmentItem<String>, IDbRecord
	{
		#region Abstract and overrides
		/// <summary>
		/// Klíčová hodnota záznamu. Potomek musí implementovat = namapovat na konkrétní property, která nese skutečný klíč záznamu.
		/// </summary>
		protected override string CurrentKeyValue { get { return this._table_name; } set { this._table_name = value; } }
		/// <summary>
		/// Číslo záznamu. Potomek musí implementovat = namapovat na konkrétní property, která nese skutečné číslo záznamu.
		/// </summary>
		// public override Int32 CurrentRecordNumber { get { return 0; } protected set { } }
		/// <summary>
		/// Vizualizace
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			return "Table " + this.TableName + "; identity=" + this.IdentityColumn;
		}
		#endregion
		#region Public data property
		///<summary>Název tabulky, včetně vlastníka, malými písmeny, typicky "lcs.subjekty"</summary>
		public string TableName { get { return _table_name; } }
        ///<summary>Název Identity sloupce, malými písmeny, pouze sloupec. Anebo null pokud tabulka nemá identity column.</summary>
		public string IdentityColumn { get { return _GetIdentityColumn(); } }
        ///<summary>Unikátní ID objektu (je přiděleno SQL serverem)</summary>
        public int ObjectId { get { return _object_id; } }
		#endregion
		#region Protected data fields
		#pragma warning disable 1591
		protected string _table_name;
        protected string _obj_type;
		protected string _identity_column;
        protected int _object_id;
		#pragma warning restore 1591
		#endregion
		#region IDbRecord
		int IDbRecord.RecordNumber { get; set; }
		/// <summary>
		/// Metoda, která umožní rychle naplnit záznam daty z přicházejícího datareaderu.
		/// Typové čtení zajišťuje mapa, metodou map.GetItem...(string columnName).
		/// Metoda má vracet true = data byla skutečně načtena a do záznamu uložena (false = nedošlo k tomu, data se budou načítat genericky).
		/// </summary>
		/// <param name="reader"></param>
		/// <param name="map"></param>
		/// <returns></returns>
		bool IDbFill.FillFromReader(SqlDataReader reader, FieldMapperLoad map)
		{
			_object_id = (int)map.FillDataIntoField<int>("object_id", reader);
			_table_name = ((string)map.FillDataIntoField<string>("table_name", reader)).ToLower();
			_obj_type = ((string)map.FillDataIntoField<string>("obj_type", reader));
			_identity_column = (string)map.FillDataIntoField<string>("identity_column", reader);
			if (_identity_column != null)
				_identity_column = _identity_column.ToLower();
			this.ObjectType = ConvertObjectType(this._obj_type);
			return true;
		}
		/// <summary>
		/// Metoda, ve které datový objekt připraví podklady pro uložení svých dat do databáze.
		/// Objekt svoje proměnné vloží do exportní mapy prostřednictvím metod map.AddTable(); map.AddColumn();
		/// Pokud objekt chce plnit více tabulek, plní je do mapy postupně, vždy v pořadí {tabulka, sloupce tabulky; další tabulka; sloupce}.
		/// Po naplnění mapy se vrací true.
		/// </summary>
		/// <param name="map"></param>
		/// <returns></returns>
		bool IDbRecord.PrepareSaveData(FieldMapperSave map)
		{ return false; }
		#endregion
		#region Static generátor SQL selectu
		/// <summary>
		/// SQL SELECT pro načtení columnů, odpovídajících této struktuře. Pozor: neobsahuje filtr ani order.
		/// </summary>
		public static string SqlSelect
		{ 
			get 
			{
                return @"SELECT obj.object_id, sch.name + '.' + obj.name as table_name, obj.type as obj_type, (select top 1 col.name from sys.columns col where col.object_id = obj.object_id and col.is_identity = 1) as identity_column
FROM sys.objects obj JOIN sys.schemas sch on sch.schema_id = obj.schema_id WHERE obj.type in ('U', 'V') ";
			}
		}
		#endregion
        #region On-Demand Columns
        /// <summary>
        /// Seznam sloupců této tabulky.
		/// Načítá se do paměti až při prvním přístupu k tomuto seznamu (on-demand, lazy initialization).
        /// </summary>
        public List<DbColumnInfo> ColumnList { get { return _GetColumnList(); } }
        private List<DbColumnInfo> _GetColumnList()
        {
            if (this._ColumnList == null)
            {
                lock (this._ColumnListWriteLock)
                {
                    if (this._ColumnList == null)
                    {
						string sql = DbColumnInfo.SqlSelect;
						sql = sql.Replace("{{ObjectId}}", this.ObjectId.ToString());
                        List<DbColumnInfo> columnList = Db_Layer.GetList<DbColumnInfo>(sql, this.ExternalDataConnector);
						foreach (DbColumnInfo dbColumnInfo in columnList)
							dbColumnInfo.TableInfo = this;
						this._ColumnList = columnList;
					}
                }
            }
            return this._ColumnList;
        }
        private object _ColumnListWriteLock = new object();
        private List<DbColumnInfo> _ColumnList;
        #endregion
        #region On-Demand Indexes
        /// <summary>
        /// Seznam indexů této tabulky.
		/// Načítá se do paměti až při prvním přístupu k tomuto seznamu (on-demand, lazy initialization).
        /// </summary>
		public List<DbIndexInfo> IndexList { get { return _GetIndexList(); } }
		private List<DbIndexInfo> _GetIndexList()
        {
			if (this._IndexList == null)
            {
				lock (this._IndexListWriteLock)
                {
					if (this._IndexList == null)
                    {
						this._IndexList = _LoadIndexList();
                    }
                }
            }
			return this._IndexList;
        }
		/// <summary>
		/// Načte seznam indexů.
		/// Indexy se načítají jedním SELECTEM spolu s jejich položkami KEY (sloupce),
		/// do prvotní třídy DbIndexKeyRecord, z níž se teprve rozdělují 
		/// do záznamů třídy DbIndexInfo (hlavička indexu) + položky DbIndexKeyInfo (columny).
		/// </summary>
		/// <returns></returns>
		private List<DbIndexInfo> _LoadIndexList()
		{
			List<DbIndexInfo> result = new List<DbIndexInfo>();
			string sql = DbIndexKeyRecord.SqlSelect;
			sql = sql.Replace("{{ObjectId}}", this.ObjectId.ToString());
            List<DbIndexKeyRecord> recordList = Db_Layer.GetList<DbIndexKeyRecord>(sql, this.ExternalDataConnector);   // Načteme prvotní záznamy, kde v jednom řádku jsou (JOIN) vedle sebe data indexu (pod sebou opakovaně) a vedle toho data jeho klíčů
			IEnumerable<IGrouping<string, DbIndexKeyRecord>> recordGroups = recordList.GroupBy(r => r.IndexName);  // Group podle jména indexu => jedna grupa = jeden index
			foreach (IGrouping<string, DbIndexKeyRecord> recordGroup in recordGroups)
			{
				DbIndexKeyRecord first = recordGroup.First();        // Grupa je charakteristická tím, že vždycky má First položku :-). Objekt First odpovídá hlavičce indexu.
				DbIndexInfo indexInfo = new DbIndexInfo(this, first.IndexId, first.IndexName, first.IndexType, first.IndexIsUnique, first.IndexIgnoreDupKey, first.IndexIsPrimaryKey, first.IndexIsUniqueConstraint, first.IndexFillFactor, first.IndexIsPadded);
				List<DbIndexKeyInfo> indexKeys = recordGroup.ToList().ConvertAll(key => new DbIndexKeyInfo(indexInfo, key.KeyId, key.KeyOrdinal, key.KeyColumnId, key.KeyColumnName, key.KeySortMode));
				indexInfo.StoreKeys(indexKeys);
				result.Add(indexInfo);
			}
			return result;
		}
		private object _IndexListWriteLock = new object();
		private List<DbIndexInfo> _IndexList;
        /// <summary>
        /// Záznam načtený z databáze pro jednu větu indexu + jeho klíče (JOIN načtený jedním selectem, teprve následně se rozdělí na DbIndexInfo a DbIndexKeyInfo
        /// </summary>
        protected class DbIndexKeyRecord : IDbRecord
        {
            #region Public data property
            /// <summary>ID indexu v rámci tabulky; sys.indexes.index</summary>
            public int IndexId { get { return _idx_id; } }
            /// <summary>Název indexu; sys.indexes.name</summary>
            public string IndexName { get { return _idx_name; } }
            /// <summary>Typ indexu (CLUSTERED / NONCLUSTERED); sys.indexes.type</summary>
            public DbIndexType IndexType { get { return DbTableInfo.ConvertDbIndexType(_idx_type); } }
            /// <summary>Je index UNIQUE; sys.indexes.is_unique</summary>
            public bool IndexIsUnique { get { return _idx_is_unique != 0; } }
            /// <summary>Má index nastaveno IGNORE_DUP_KEY; sys.indexes.ignore_dup_key</summary>
            public bool IndexIgnoreDupKey { get { return _idx_ignore_dup_key != 0; } }
            /// <summary>Je index PRIMARY KEY CONSTRAINT; sys.indexes.is_primary_key</summary>
            public bool IndexIsPrimaryKey { get { return _idx_is_primary_key != 0; } }
            /// <summary>Je index UNIQUE CONSTRAINT; sys.indexes.is_unique_constraint</summary>
            public bool IndexIsUniqueConstraint { get { return _idx_is_unique_constraint != 0; } }
            /// <summary>Hodnota FILL FACTORY; sys.indexes.fill_factor</summary>
            public int IndexFillFactor { get { return _idx_fill_factor; } }
            /// <summary>Je index PADING ON; sys.indexes.is_padded</summary>
            public bool IndexIsPadded { get { return _idx_is_padded != 0; } }
            /// <summary>Sloupec indexu, ID v rámci indexu; sys.index_columns.index_column_id</summary>
            public int KeyId { get { return _key_index_column_id; } }
            /// <summary>Sloupec indexu, pořadí v rámci indexu; sys.index_columns.key_ordinal</summary>
            public int KeyOrdinal { get { return _key_key_ordinal; } }
            /// <summary>Sloupec indexu, ID sloupce; sys.index_columns.column_id</summary>
            public int KeyColumnId { get { return _key_column_id; } }
            /// <summary>Sloupec indexu, název sloupce; sys.columns.name</summary>
            public string KeyColumnName { get { return _key_column_name; } }
            /// <summary>Sloupec indexu, směr (ASC / DESC); sys.index_columns.is_descending_key</summary>
			public DbSortMode KeySortMode { get { return DbTableInfo.ConvertDbSortMode(_key_is_descending_key); } }
			/// <summary>Vizualizace</summary>
			/// <returns></returns>
			public override string ToString()
			{
				return "IndexName: " + this.IndexName + "; ColumnName: " + this.KeyColumnName;
			}
            #endregion
            #region Protected data fields
#pragma warning disable 1591
            protected int _idx_id;
            protected string _idx_name;
            protected int _idx_type;
            protected int _idx_is_unique;
            protected int _idx_ignore_dup_key;
            protected int _idx_is_primary_key;
            protected int _idx_is_unique_constraint;
            protected int _idx_fill_factor;
            protected int _idx_is_padded;
            protected int _key_index_column_id;
            protected int _key_key_ordinal;
            protected int _key_column_id;
            protected string _key_column_name;
            protected int _key_is_descending_key;
#pragma warning restore 1591
            #endregion
            #region IDbRecord
            int IDbRecord.RecordNumber { get; set; }
            /// <summary>
            /// Metoda, která umožní rychle naplnit záznam daty z přicházejícího datareaderu.
            /// Typové čtení zajišťuje mapa, metodou map.GetItem...(string columnName).
            /// Metoda má vracet true = data byla skutečně načtena a do záznamu uložena (false = nedošlo k tomu, data se budou načítat genericky).
            /// </summary>
            /// <param name="reader"></param>
            /// <param name="map"></param>
            /// <returns></returns>
            bool IDbFill.FillFromReader(SqlDataReader reader, FieldMapperLoad map)
            {
				_idx_id = (int)map.FillDataIntoField<int>("idx_id", reader);
				_idx_name = (string)map.FillDataIntoField<string>("idx_name", reader);
                if (_idx_name != null)
                    _idx_name = _idx_name.ToLower();
				_idx_type = (int)map.FillDataIntoField<int>("idx_type", reader);
				_idx_is_unique = (int)map.FillDataIntoField<int>("idx_is_unique", reader);
				_idx_ignore_dup_key = (int)map.FillDataIntoField<int>("idx_ignore_dup_key", reader);
				_idx_is_primary_key = (int)map.FillDataIntoField<int>("idx_is_primary_key", reader);
				_idx_is_unique_constraint = (int)map.FillDataIntoField<int>("idx_is_unique_constraint", reader);
				_idx_fill_factor = (int)map.FillDataIntoField<int>("idx_fill_factor", reader);
				_idx_is_padded = (int)map.FillDataIntoField<int>("idx_is_padded", reader);
				_key_index_column_id = (int)map.FillDataIntoField<int>("key_index_column_id", reader);
				_key_key_ordinal = (int)map.FillDataIntoField<int>("key_key_ordinal", reader);
				_key_column_id = (int)map.FillDataIntoField<int>("key_column_id", reader);
				_key_column_name = (string)map.FillDataIntoField<string>("key_column_name", reader);
                if (_key_column_name != null)
                    _key_column_name = _key_column_name.ToLower();
				_key_is_descending_key = (int)map.FillDataIntoField<int>("key_is_descending_key", reader);
                return true;
            }
            /// <summary>
            /// Metoda, ve které datový objekt připraví podklady pro uložení svých dat do databáze.
            /// Objekt svoje proměnné vloží do exportní mapy prostřednictvím metod map.AddTable(); map.AddColumn();
            /// Pokud objekt chce plnit více tabulek, plní je do mapy postupně, vždy v pořadí {tabulka, sloupce tabulky; další tabulka; sloupce}.
            /// Po naplnění mapy se vrací true.
            /// </summary>
            /// <param name="map"></param>
            /// <returns></returns>
            bool IDbRecord.PrepareSaveData(FieldMapperSave map)
            { return false; }
            #endregion
            #region Static generátor SQL selectu
            /// <summary>
            /// SQL SELECT pro načtení columnů, odpovídajících této struktuře. Pozor: zde OBSAHUJE FILTR a ORDER BY. 
            /// Filtr je postaven na jednu tabulku, je třeba znát její ID a vložit jej namísto tokenu {{ObjectId}}
            /// </summary>
            public static string SqlSelect
            {
                get
                {
                    return @"SELECT
 idx.index_id as idx_id,
 idx.name as idx_name,
 idx.type as idx_type,
 idx.type_desc as idx_type_desc,
 idx.is_unique as idx_is_unique,
 idx.ignore_dup_key as idx_ignore_dup_key,
 idx.is_primary_key as idx_is_primary_key,
 idx.is_unique_constraint as idx_is_unique_constraint,
 idx.fill_factor as idx_fill_factor,
 idx.is_padded as idx_is_padded,
 idk.index_column_id as key_index_column_id,
 idk.key_ordinal as key_key_ordinal,
 idk.column_id as key_column_id,
 col.name as key_column_name,
 idk.is_descending_key as key_is_descending_key
FROM sys.indexes idx
 join sys.index_columns idk on idk.object_id = idx.object_id and idk.index_id = idx.index_id
 join sys.columns col on col.object_id = idx.object_id and col.column_id = idk.column_id
WHERE idx.object_id = {{ObjectId}}
ORDER BY idx.index_id, idk.key_ordinal";
                }
            }
            #endregion
        }
        #endregion
        #region On-Demand Classes
        /// <summary>
        /// Seznam tříd, které používají tuto tabulku.
        /// Načítá se do paměti až při prvním přístupu k tomuto seznamu (on-demand, lazy initialization).
        /// </summary>
        public List<ClassInfo> ClassList { get { return this._GetClassList(); } }
        private List<ClassInfo> _GetClassList()
        {
            if (this._ClassNumberList == null)
            {
                lock (this._ClassListWriteLock)
                {
                    if (this._ClassNumberList == null)
                    {
                        List<int> classList = this._LoadClassNumberList();
                        if (classList != null && classList.Count > 1)
                            classList.Sort();
                        this._ClassNumberList = classList;
                    }
                }
            }
            return Repository.Classes.GetList(this._ClassNumberList);
        }
        private List<int> _LoadClassNumberList()
        {
            string tableName = this.TableName;
            string objectName = tableName;
            if (objectName.Contains("."))
                objectName = objectName.Substring(objectName.IndexOf('.') + 1);
            string sql = "SELECT cislo_tridy FROM lcs.noris_classes WHERE nazev_tabulky = '" + objectName + "' or tabulka_objects = '" + objectName + "' or (enable_uda='A' and uda_table = '" + tableName + "')or (enable_udapol='A' and udapol_table = '" + tableName + "')";
            return Db_Layer.GetList<int>(sql, this.ExternalDataConnector);
        }
        private object _ClassListWriteLock = new object();
        private List<int> _ClassNumberList;
        #endregion
        #region Další property a metody
        /// <summary>
        /// Typ objektu.
        /// Zde přichází do úvahy pouze TableUserDefined anebo View.
        /// </summary>
        public DbObjectType ObjectType { get; private set; }
        /// <summary>
        /// Zkusí najít sloupec daného jména (columnName).
        /// Vrací true = našli jsme jej, sloupec ukládá do out parametru columnInfo.
        /// </summary>
        /// <param name="columnName"></param>
        /// <param name="columnInfo"></param>
        /// <returns></returns>
        public bool TryFindColumn(string columnName, out DbColumnInfo columnInfo)
        {
            columnInfo = this.FindColumn(columnName);
            return (columnInfo != null);
        }
		/// <summary>
        /// Zjistí, zda tato tabulka obsahuje sloupec daného jména (columnName).
		/// Sloupec má být zadaný bez názvu tabulky.
		/// </summary>
		/// <param name="columnName"></param>
		/// <returns></returns>
		public bool ContainColumn(string columnName)
		{
            return (this.FindColumn(columnName) != null);
		}
        /// <summary>
        /// Metoda vrátí informace o sloupci daného názvu (columnName).
        /// Sloupec má být zadaný bez názvu tabulky.
        /// Pokud neexistuje, vrací null.
        /// </summary>
        /// <param name="columnName"></param>
        /// <returns></returns>
        public DbColumnInfo FindColumn(string columnName)
        {
            if (String.IsNullOrEmpty(columnName)) return null;
            string colName = columnName.Trim().ToLower();
            return this.ColumnList.FirstOrDefault(c => c.ColumnName == colName);
        }
        /// <summary>
        /// Vrátí identity column.
        /// </summary>
        /// <returns></returns>
        private string _GetIdentityColumn()
        {
            string identityColumn = this._identity_column;
            if (!String.IsNullOrEmpty(identityColumn)) return identityColumn;

            if (this.ObjectType == DbObjectType.View)
            {   // View nemusejí mít identity column
                List<DbColumnInfo> columnList = this.ColumnList;
                DbColumnInfo columnInfo = columnList.FirstOrDefault(c => c.TypeName == "int");
                if (columnInfo != null)
                    this._identity_column = columnInfo.ColumnName;
            }
            return this._identity_column;
        }
        
        #endregion
		#region Static metody - konverze typů a další služby
		/// <summary>
		/// Vrátí typ DB objektu (DbObjectType) na základě jeho kódu uvedeného v sys.objects.type.
		/// </summary>
		/// <param name="objType"></param>
		/// <returns></returns>
		public static DbObjectType ConvertObjectType(string objType)
		{
			if (objType == null) return DbObjectType.None;
			switch (objType.Trim())            // Text v objType typicky přichází jako char(2), tedy "U " nebo "V " (s mezerou na konci). Odeberu mezery.
			{
				case "AF": return DbObjectType.AggregateFunctionCLR;
				case "C": return DbObjectType.CheckConstraint;
				case "D": return DbObjectType.DefaulConstraint;
				case "F": return DbObjectType.ForeignKeyConstraint;
				case "FN": return DbObjectType.SqlScalarFunction;
				case "FS": return DbObjectType.AssemblyClrScalarFunction;
				case "FT": return DbObjectType.AssemblyClrTableValuedFunction;
				case "IF": return DbObjectType.SqlInlineTableValuedFunction;
				case "IT": return DbObjectType.InternalTable;
				case "P": return DbObjectType.SqlStoredProcedure;
				case "PC": return DbObjectType.AssemblyClrStoredProcedure;
				case "PG": return DbObjectType.PlanGuide;
				case "PK": return DbObjectType.PrimaryKeyConstraint;
				case "R": return DbObjectType.RuleOldStyleStandAlone;
				case "RF": return DbObjectType.ReplicationFilterProcedure;
				case "S": return DbObjectType.SystemBaseTable;
				case "SN": return DbObjectType.Synonym;
				case "SQ": return DbObjectType.ServiceQueue;
				case "TA": return DbObjectType.AssemblyClrDmlTrigger;
				case "TF": return DbObjectType.SqlTableValuedFunction;
				case "TR": return DbObjectType.SqlDmlTrigger;
				case "TT": return DbObjectType.TableType;
				case "U": return DbObjectType.TableUserDefined;
				case "UQ": return DbObjectType.UniqueConstraint;
				case "V": return DbObjectType.View;
				case "X": return DbObjectType.ExtendedStoredProcedure;
			}
			return DbObjectType.None;
		}
		/// <summary>
		/// Vrátí typ indexu na základě jeho DB čísla
		/// </summary>
		/// <param name="dbIndexType"></param>
		/// <returns></returns>
		public static DbIndexType ConvertDbIndexType(int dbIndexType)
		{
			switch (dbIndexType)
			{
				case 0: return DbIndexType.Heap;
				case 1: return DbIndexType.Clustered;
				case 2: return DbIndexType.Nonclustered;
			}
			return DbIndexType.None;
		}
		/// <summary>
		/// Vrátí DB číslo odpovídající typu indexu
		/// </summary>
		/// <param name="dbIndexType"></param>
		/// <returns></returns>
		public static int ConvertDbIndexType(DbIndexType dbIndexType)
		{
			switch (dbIndexType)
			{
				case DbIndexType.Heap: return 0;
				case DbIndexType.Clustered: return 1;
				case DbIndexType.Nonclustered: return 2;
			}
			return 99;
		}
		/// <summary>
		/// Vrátí druh třídění na základě jeho DB čísla
		/// </summary>
		/// <param name="dbSortMode"></param>
		/// <returns></returns>
		public static DbSortMode ConvertDbSortMode(int dbSortMode)
		{
			switch (dbSortMode)
			{
				case 0: return DbSortMode.Ascending;
				case 1: return DbSortMode.Descending;
			}
			return DbSortMode.None;
		}
		/// <summary>
		/// Vrátí DB číslo odpovídající typu třídění
		/// </summary>
		/// <param name="dbSortMode"></param>
		/// <returns></returns>
		public static int ConvertDbSortMode(DbSortMode dbSortMode)
		{
			switch (dbSortMode)
			{
				case DbSortMode.Ascending: return 0;
				case DbSortMode.Descending: return 1;
			}
			return 0;
		}
        /// <summary>
        /// Rozdělí daný plný název sloupce (owner.table.column) na tabulku (owner.table) a sloupec (column), rozdělí v místě poslední tečky.
        /// Vrací true, pokud zadaná data (fullColumnName) není prázdné, a nezačíná číslicí. Pak provede rozdělení.
        /// Vrací false, když fullColumnName nemůže být sloupcem.
        /// </summary>
        /// <param name="fullColumnName"></param>
        /// <param name="tableName"></param>
        /// <param name="columnName"></param>
        public static bool SplitFullDbColumn(string fullColumnName, out string tableName, out string columnName)
        {
            return SplitFullDbColumn(fullColumnName, false, out tableName, out columnName);
        }
        /// <summary>
        /// Rozdělí daný plný název sloupce (owner.table.column) na tabulku (owner.table) a sloupec (column), rozdělí v místě poslední tečky.
        /// Vrací true, pokud zadaná data (fullColumnName) není prázdné, a nezačíná číslicí. Pak provede rozdělení.
        /// Vrací false, když fullColumnName nemůže být sloupcem.
        /// </summary>
        /// <param name="fullColumnName"></param>
        /// <param name="tableName"></param>
        /// <param name="columnName"></param>
        public static bool SplitFullDbColumn(string fullColumnName, bool enableConstans, out string tableName, out string columnName)
        {
            tableName = null;
            columnName = null;
            if (String.IsNullOrEmpty(fullColumnName)) return false;
            fullColumnName = fullColumnName.Trim();
            if (fullColumnName.Length == 0) return false;
            if (!enableConstans && "0123456789".IndexOf(fullColumnName[0]) >= 0) return false;

            int index = fullColumnName.LastIndexOf('.');
            if (index <= 0)
            {
                tableName = "";
                columnName = fullColumnName;
            }
            else if (index < (fullColumnName.Length - 1))
            {
                tableName = fullColumnName.Substring(0, index);
                columnName = fullColumnName.Substring(index + 1);
            }
            else
            {
                tableName = fullColumnName;
                columnName = "";
            }
            tableName = tableName.Trim().ToLower();
            columnName = columnName.Trim().ToLower();
            return true;        
        }
		#endregion
    }
    /// <summary>
    /// Informace o jednom databázovém sloupci
    /// </summary>
    public class DbColumnInfo : IDbRecord
    {
        #region KONSTRUKCE
        /// <summary>
        /// Vizualizace
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return "Table: " + this.TableInfo.TableName + "; Column: " + this.ColumnName + " (" + this.TypeName + ")";
        }
        #endregion
        #region Public data property
        ///<summary>ID sloupce v rámci tabulky, odpovídá pořadí, začíná 1</summary>
        public int ColumnId { get { return _col_id; } }
        ///<summary>Název db sloupce, malými písmeny</summary>
        public string ColumnName { get { return _column_name; } }
        ///<summary>Název typu: int, bigint, varchar, smalldatetime, numeric_19_6, datetime, char</summary>
        public string TypeName { get { return _typ_name; } }
        ///<summary>Délka dat uvedená explicitně ve sloupci</summary>
        public int ColumnLength { get { return _column_length; } }
        ///<summary>Délka dat uvedená v typu</summary>
        public int TypeLength { get { return _typ_length; } }
        ///<summary>Přesnost dat uvedená explicitně ve sloupci</summary>
        public int ColumnPrecision { get { return _column_precision; } }
        ///<summary>Přesnost dat uvedená v typu</summary>
        public int TypePrecision { get { return _typ_precision; } }
        ///<summary>Měřítko dat uvedené explicitně ve sloupci</summary>
        public int ColumnScale { get { return _column_scale; } }
        ///<summary>Měřítko dat uvedené v typu</summary>
        public int TypeScale { get { return _typ_scale; } }
        ///<summary>Příznak, že tento sloupec je Identity</summary>
        public bool IsIdentity { get { return (_is_identity != 0); } }
        ///<summary>Příznak, že tento sloupec je Nullable</summary>
        public bool IsNullable { get { return (_is_nullable != 0); } }
        ///<summary>Příznak, že tento sloupec je AnsiPadding ON</summary>
        public bool IsAnsiPadding { get { return (_is_ansi_padding != 0); } }
        ///<summary>Příznak, že tento sloupec je Computed (není ukládaná do tabulky, ale je počítaný)</summary>
        public bool IsComputed { get { return (_is_computed != 0); } }
        ///<summary>Příznak, že tento sloupec má default</summary>
        public bool HasDefault { get { return (!String.IsNullOrEmpty(_default_name)); } }
        ///<summary>Název constraintu Default</summary>
        public string DefaultName { get { return _default_name; } }
        ///<summary>Text defaultu (v SQL vyjádření, tedy typicky kupa závorek okolo, například: ('P'), ((0)), ('01.01.1900')</summary>
        public string DefaultText { get { return _default_text; } }
        ///<summary>Výpočtový výraz</summary>
        public string ComputeExpression { get { return _compute_expr; } }
        #endregion
        #region Protected data fields
#pragma warning disable 1591
        protected int _col_id;
        protected string _column_name;
        protected string _typ_name;
        protected int _column_length;
        protected int _typ_length;
        protected int _column_precision;
        protected int _typ_precision;
        protected int _column_scale;
        protected int _typ_scale;
        protected int _is_identity;
        protected int _is_nullable;
        protected int _is_ansi_padding;
        protected int _is_computed;
        protected string _default_name;
        protected string _default_text;
        protected string _compute_expr;
#pragma warning restore 1591
        #endregion
		#region IDbRecord
		int IDbRecord.RecordNumber { get; set; }
		/// <summary>
		/// Metoda, která umožní rychle naplnit záznam daty z přicházejícího datareaderu.
		/// Typové čtení zajišťuje mapa, metodou map.GetItem...(string columnName).
		/// Metoda má vracet true = data byla skutečně načtena a do záznamu uložena (false = nedošlo k tomu, data se budou načítat genericky).
		/// </summary>
		/// <param name="reader"></param>
		/// <param name="map"></param>
		/// <returns></returns>
		bool IDbFill.FillFromReader(SqlDataReader reader, FieldMapperLoad map)
		{
			_col_id = (int)map.FillDataIntoField<int>("col_id", reader);
			_column_name = (string)map.FillDataIntoField<string>("column_name", reader);
			if (_column_name != null)
				_column_name = _column_name.ToLower();
			_typ_name = (string)map.FillDataIntoField<string>("typ_name", reader);
			_column_length = (int)map.FillDataIntoField<int>("column_length", reader);
			_typ_length = (int)map.FillDataIntoField<int>("typ_length", reader);
			_column_precision = (int)map.FillDataIntoField<int>("column_precision", reader);
			_typ_precision = (int)map.FillDataIntoField<int>("typ_precision", reader);
			_column_scale = (int)map.FillDataIntoField<int>("column_scale", reader);
			_typ_scale = (int)map.FillDataIntoField<int>("typ_scale", reader);
			_is_identity = (int)map.FillDataIntoField<int>("is_identity", reader);
			_is_nullable = (int)map.FillDataIntoField<int>("is_nullable", reader);
			_is_ansi_padding = (int)map.FillDataIntoField<int>("is_ansi_padding", reader);
			_is_computed = (int)map.FillDataIntoField<int>("is_computed", reader);
			_default_name = (string)map.FillDataIntoField<string>("default_name", reader);
			_default_text = (string)map.FillDataIntoField<string>("default_text", reader);
			_compute_expr = (string)map.FillDataIntoField<string>("compute_expr", reader);
			return true;
		}
		/// <summary>
		/// Metoda, ve které datový objekt připraví podklady pro uložení svých dat do databáze.
		/// Objekt svoje proměnné vloží do exportní mapy prostřednictvím metod map.AddTable(); map.AddColumn();
		/// Pokud objekt chce plnit více tabulek, plní je do mapy postupně, vždy v pořadí {tabulka, sloupce tabulky; další tabulka; sloupce}.
		/// Po naplnění mapy se vrací true.
		/// </summary>
		/// <param name="map"></param>
		/// <returns></returns>
		bool IDbRecord.PrepareSaveData(FieldMapperSave map)
		{ return false; }
		#endregion
        #region Static generátor SQL selectu
        /// <summary>
        /// SQL SELECT pro načtení columnů, odpovídajících této struktuře. Pozor: zde OBSAHUJE FILTR a ORDER BY. 
        /// Filtr je postaven na jednu tabulku, je třeba znát její ID a vložit jej namísto tokenu {{ObjectId}}
        /// </summary>
        public static string SqlSelect
        {
            get
            {
                return @"SELECT 
 col.column_id as col_id,
 col.name as column_name,
 typ.name as typ_name,
 col.max_length as column_length,
 typ.max_length as typ_length,
 col.precision as column_precision,
 typ.precision as typ_precision,
 col.scale as column_scale,
 typ.scale as typ_scale,
 col.is_identity as is_identity,
 col.is_nullable as is_nullable,
 col.is_ansi_padded as is_ansi_padding,
 col.is_computed as is_computed,
 defa.name as default_name,
 defa.definition as default_text,
 comp.definition as compute_expr
FROM sys.columns col 
 left outer join sys.types typ on typ.user_type_id = col.user_type_id
 left outer join sys.default_constraints defa on defa.object_id = col.default_object_id
 left outer join sys.computed_columns comp on comp.object_id = col.object_id and comp.column_id = col.column_id
WHERE col.object_id = {{ObjectId}}
ORDER BY col.column_id";
            }
        }
        #endregion
        #region Extended property
        public DbTableInfo TableInfo { get; internal set; }
        #endregion
    }
    /// <summary>
    /// Informace o jednom indexu (název, vlastnosti, seznam klíčových sloupců)
    /// </summary>
    public class DbIndexInfo 
    {
        #region Konstrukce
        internal DbIndexInfo(DbTableInfo tableInfo, int indexId, string indexName, DbIndexType indexType, bool indexIsUnique, bool indexIgnoreDupKey, bool indexIsPrimaryKey, bool indexIsUniqueConstraint, int indexFillFactor, bool indexIsPadded)
        {
            this.TableInfo = tableInfo;
            this.IndexId = indexId;
            this.IndexName = indexName;
            this.IndexType = indexType;
            this.IndexIsUnique = indexIsUnique;
            this.IndexIgnoreDupKey = indexIgnoreDupKey;
            this.IndexIsPrimaryKey = indexIsPrimaryKey;
            this.IndexIsUniqueConstraint = indexIsUniqueConstraint;
            this.IndexFillFactor = indexFillFactor;
            this.IndexIsPadded = indexIsPadded;

			this.Keys = null;
        }
		/// <summary>
		/// Vloží soupis klíčových sloupců
		/// </summary>
		/// <param name="keys"></param>
		internal void StoreKeys(List<DbIndexKeyInfo> keys)
		{
			if (this.Keys != null)
				Throw.SysError(MessageInfo.Get("Chyba v konstrukci indexu %0:%1 : do indexu nelze vložit soupis klíčů více než jednou.", this.TableInfo.TableName, this.IndexName));
			if (keys == null)
				Throw.SysError(MessageInfo.Get("Chyba v konstrukci indexu %0:%1 : do indexu nelze vložit namísto soupisu klíčů hodnotu null.", this.TableInfo.TableName, this.IndexName));
			if (keys.Count > 1)
				keys.Sort((a, b) => a.KeyOrdinal.CompareTo(b.KeyOrdinal));
			this.Keys = keys;
		}
		/// <summary>Vizualizace</summary>
		/// <returns></returns>
		public override string ToString()
		{
			return "Index: " + this.IndexName + "; On table: " + this.TableInfo.TableName;
		}
		#endregion
        #region Property
        /// <summary>Tabulka, do níž index patří</summary>
        public DbTableInfo TableInfo { get; private set; }
        /// <summary>ID indexu v rámci tabulky; sys.indexes.index</summary>
        public int IndexId { get; private set; }
        /// <summary>Název indexu; sys.indexes.name</summary>
        public string IndexName { get; private set; }
        /// <summary>Typ indexu (CLUSTERED / NONCLUSTERED); sys.indexes.type</summary>
        public DbIndexType IndexType { get; private set; }
        /// <summary>Je index UNIQUE; sys.indexes.is_unique</summary>
        public bool IndexIsUnique { get; private set; }
        /// <summary>Má index nastaveno IGNORE_DUP_KEY; sys.indexes.ignore_dup_key</summary>
        public bool IndexIgnoreDupKey { get; private set; }
        /// <summary>Je index PRIMARY KEY CONSTRAINT; sys.indexes.is_primary_key</summary>
        public bool IndexIsPrimaryKey { get; private set; }
        /// <summary>Je index UNIQUE CONSTRAINT; sys.indexes.is_unique_constraint</summary>
        public bool IndexIsUniqueConstraint { get; private set; }
        /// <summary>Hodnota FILL FACTORY; sys.indexes.fill_factor</summary>
        public int IndexFillFactor { get; private set; }
        /// <summary>Je index PADING ON; sys.indexes.is_padded</summary>
        public bool IndexIsPadded { get; private set; }
        /// <summary>Soupis klíčů indexu</summary>
        public IEnumerable<DbIndexKeyInfo> Keys { get; private set; }
        #endregion
	}
    /// <summary>
    /// Informace o jednom klíči v rámci indexu (název, vlastnosti)
    /// </summary>
    public class DbIndexKeyInfo
    {
        #region Konstrukce
        internal DbIndexKeyInfo(DbIndexInfo indexInfo, int keyId, int keyOrdinal, int keyColumnId, string keyColumnName, DbSortMode keySortMode)
        {
            this.IndexInfo = indexInfo;
            this.KeyId = keyId;
            this.KeyOrdinal = keyOrdinal;
            this.KeyColumnId = keyColumnId;
            this.KeyColumnName = keyColumnName;
            this.KeySortMode = keySortMode;
        }
		/// <summary>Vizualizace</summary>
		/// <returns></returns>
		public override string ToString()
		{
			return this.IndexInfo.ToString() + "; KeyColumn: " + this.KeyColumnName;
		}
		#endregion
        #region Property
        /// <summary>Index, do něhož tento klíčový sloupec patří</summary>
        public DbIndexInfo IndexInfo { get; private set; }
        /// <summary>Sloupec indexu, ID v rámci indexu; sys.index_columns.index_column_id</summary>
        public int KeyId { get; private set; }
        /// <summary>Sloupec indexu, pořadí v rámci indexu; sys.index_columns.key_ordinal</summary>
        public int KeyOrdinal { get; private set; }
        /// <summary>Sloupec indexu, ID sloupce; sys.index_columns.column_id</summary>
        public int KeyColumnId { get; private set; }
        /// <summary>Sloupec indexu, název sloupce; sys.columns.name</summary>
        public string KeyColumnName { get; private set; }
        /// <summary>Sloupec indexu, směr (ASC / DESC); sys.index_columns.is_descending_key</summary>
        public DbSortMode KeySortMode { get; private set; }
        #endregion
    }
    /// <summary>
    /// Druh databázového objektu (sys.objects.type)
    /// </summary>
    public enum DbObjectType
    {
		/// <summary>0=nic</summary>
        None = 0,
        /// <summary>AF</summary>
        AggregateFunctionCLR,
        /// <summary>C</summary>
        CheckConstraint,
        /// <summary>D</summary>
        DefaulConstraint,
        /// <summary>F</summary>
        ForeignKeyConstraint,
        /// <summary>FN</summary>
        SqlScalarFunction,
        /// <summary>FS</summary>
        AssemblyClrScalarFunction,
        /// <summary>FT</summary>
        AssemblyClrTableValuedFunction,
        /// <summary>IF</summary>
        SqlInlineTableValuedFunction,
        /// <summary>IT</summary>
        InternalTable,
        /// <summary>P</summary>
        SqlStoredProcedure,
        /// <summary>PC</summary>
        AssemblyClrStoredProcedure,
        /// <summary>PG</summary>
        PlanGuide,
        /// <summary>PK</summary>
        PrimaryKeyConstraint,
        /// <summary>R</summary>
        RuleOldStyleStandAlone,
        /// <summary>RF</summary>
        ReplicationFilterProcedure,
        /// <summary>S</summary>
        SystemBaseTable,
        /// <summary>SN</summary>
        Synonym,
        /// <summary>SQ</summary>
        ServiceQueue,
        /// <summary>TA</summary>
        AssemblyClrDmlTrigger,
        /// <summary>TF</summary>
        SqlTableValuedFunction,
        /// <summary>TR</summary>
        SqlDmlTrigger,
        /// <summary>TT</summary>
        TableType,
        /// <summary>U</summary>
        TableUserDefined,
        /// <summary>UQ</summary>
        UniqueConstraint,
        /// <summary>V</summary>
        View,
        /// <summary>X</summary>
        ExtendedStoredProcedure
    }
	/// <summary>
	/// Druh indexu
	/// </summary>
    public enum DbIndexType
    {
		/// <summary>0 = Heap</summary>
        Heap = 0,
		/// <summary>1 = Clustered</summary>
		Clustered = 1,
		/// <summary>2 = Nonclustered</summary>
		Nonclustered = 2,
		/// <summary>99 = None</summary>
		None = 99
    }
	/// <summary>
	/// Druh třídění
	/// </summary>
    public enum DbSortMode
    {
		/// <summary>0 = Ascending</summary>
        Ascending = 0,
		/// <summary>1 = Descending</summary>
		Descending = 1,
		/// <summary>99 = None</summary>
		None = 99
    }
	#endregion
	#region CLASS FoldersCls + FolderInfo
	/// <summary>
	/// Sada pořadačů
	/// </summary>
	public class FoldersCls : RepositorySegmentCls<Int32, FolderInfo>
	{
		/// <summary>
		/// Konstruktor. Na vstupu očekává maximální počet záznamů, které může držet v paměti.
		/// Pokud by načítal další záznamy, pak nejstarší z paměti uvolní.
		/// </summary>
		/// <param name="maxItemCnt">Nejvyšší počet záznamů. -1 = neomezeně. 0 = žádný !!!</param>
		public FoldersCls(int maxItemCnt)
			: base(maxItemCnt)
		{ }
		/// <summary>
		/// Tato property vrátí SQL SELECT pro načtení jednoho záznamu s daty.
		/// SQL SELECT musí ve vhodném místě obsahovat token {{RecordNumber}}, na jehož místo jádro dosadí číslo hledaného záznamu nebo seznam čísel.
		/// Konkrétně, select by měl obsahovat frázi: "WHERE cislo_tridy {{RecordNumber}}", 
		/// jádro pak dosadí buď "WHERE cislo_tridy = 12345", 
		/// anebo dosadí "WHERE cislo_tridy in (1,2,3,4,5,6,7)", podle požadavku.
		/// Kdo nemá rád explicitní texty, určitě rád použije konstantu TOKEN_RECORD_NUMBER.
		/// </summary>
		protected override string SqlSelect
		{
			get
			{
				return FolderInfo.SqlSelect + " WHERE cislo_poradace " + TOKEN_RECORD_NUMBER;
			}
		}
		/// <summary>
		/// Háček volaný po načtení záznamu z databáze.
		/// Háček se volá i když je přepsaná virtuální metoda this.GetDataItem(), je volán před háčkem DataItemAddBefore() / DataItemValidateBefore()
		/// </summary>
		/// <param name="item"></param>
		protected override void DataItemRetrieveAfter(FolderInfo item)
		{
			base.DataItemRetrieveAfter(item);
		}
	}
	/// <summary>
	/// Jedna položka pořadače
	/// </summary>
	public class FolderInfo : RepositorySegmentItem<Int32>, IDbRecord
	{
		#region Abstract and overrides
		/// <summary>
		/// Klíčová hodnota záznamu. Potomek musí implementovat = namapovat na konkrétní property, která nese skutečný klíč záznamu.
		/// </summary>
		protected override int CurrentKeyValue { get { return this._cislo_poradace; } set { this._cislo_poradace = value; } }
		/// <summary>
		/// Číslo záznamu. Potomek musí implementovat = namapovat na konkrétní property, která nese skutečné číslo záznamu.
		/// </summary>
		// public override Int32 CurrentRecordNumber { get { return this._cislo_poradace; } protected set { this._cislo_poradace = value; } }
		/// <summary>
		/// Vizualizace
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			return "Folder " + this.CisloPoradace.ToString() + ": " + this.Nazev;
		}
		#endregion
		#region Public data property
		///<summary><para>Atribut: Číslo pořadače</para><para>Db: lcs.poradace.cislo_poradace (int not null)</para></summary>
		public int CisloPoradace { get { return _cislo_poradace; } }
		///<summary><para>Atribut: Název</para><para>Db: lcs.poradace.nazev (varchar (40) not null)</para></summary>
		public string Nazev { get { return _nazev; } }
		///<summary><para>Atribut: Bitmapa</para><para>Db: lcs.poradace.bmp_name (varchar (40) null)</para></summary>
		public string BmpName { get { return _bmp_name; } }
		///<summary><para>Vztah 6259: Třida (zprava: Pořadače)</para><para>Db: lcs.poradace.cislo_tridy (int not null)</para></summary>
		public int CisloTridy { get { return _cislo_tridy; } }
		///<summary><para>Db: lcs.poradace.druh (char (10) null)</para></summary>
		public string Druh { get { return _druh; } }
		///<summary><para>Atribut: Reference</para><para>Db: lcs.poradace.reference_poradace (varchar (10) null)</para></summary>
		public string ReferencePoradace { get { return _reference_poradace; } }
		///<summary><para>Db: lcs.poradace.obdobi (bigint null)</para></summary>
		public SqlInt64 Obdobi { get { return _obdobi; } }
		///<summary><para>Atribut: Hrát na období [typ_ano_ne] {"A"=Ano; "N"=Ne}</para><para>Db: lcs.poradace.hrat_na_obdobi (char (1) not null)</para></summary>
		public string HratNaObdobi { get { return _hrat_na_obdobi; } }
		///<summary><para>Atribut: Generovat referenci hierarchicky</para><para>Db: lcs.poradace.priznak_hier (char (1) null)</para></summary>
		public string PriznakHier { get { return _priznak_hier; } }
		///<summary><para>Atribut: Zobrazovat kategorie</para><para>Db: lcs.poradace.dyn_cg (smallint null)</para></summary>
		public SqlInt16 DynCg { get { return _dyn_cg; } }
		///<summary><para>Atribut: Zobrazovat DV pro hlavičku</para><para>Db: lcs.poradace.dyn_ss (smallint null)</para></summary>
		public SqlInt16 DynSs { get { return _dyn_ss; } }
		///<summary><para>Atribut: Zobrazovat DV pro položky</para><para>Db: lcs.poradace.dyn_os (smallint null)</para></summary>
		public SqlInt16 DynOs { get { return _dyn_os; } }
		///<summary><para>Atribut: Archivní [typ_ano_ne] {"A"=Ano; "N"=Ne}</para><para>Db: lcs.poradace.archival (char (1) not null)</para></summary>
		public string Archival { get { return _archival; } }
		///<summary><para>Atribut: Generovat referenci lineárně</para><para>Db: lcs.poradace.generate_reference (char (1) null)</para></summary>
		public string GenerateReference { get { return _generate_reference; } }
		///<summary><para>Atribut: Maska</para><para>Db: lcs.poradace.maska (varchar (100) null)</para></summary>
		public string Maska { get { return _maska; } }
		#endregion
		#region Protected data fields
		#pragma warning disable 1591
		protected int _cislo_poradace;
		protected string _nazev;
		protected string _bmp_name;
		protected int _cislo_tridy;
		protected string _druh;
		protected string _reference_poradace;
		protected SqlInt64 _obdobi;
		protected string _hrat_na_obdobi;
		protected string _priznak_hier;
		protected SqlInt16 _dyn_cg;
		protected SqlInt16 _dyn_ss;
		protected SqlInt16 _dyn_os;
		protected string _archival;
		protected string _generate_reference;
		protected string _maska;
		#pragma warning restore 1591
		#endregion
		#region IDbRecord
		int IDbRecord.RecordNumber { get; set; }
		/// <summary>
		/// Metoda, která umožní rychle naplnit záznam daty z přicházejícího datareaderu.
		/// Typové čtení zajišťuje mapa, metodou map.GetItem...(string columnName).
		/// Metoda má vracet true = data byla skutečně načtena a do záznamu uložena (false = nedošlo k tomu, data se budou načítat genericky).
		/// </summary>
		/// <param name="reader"></param>
		/// <param name="map"></param>
		/// <returns></returns>
		bool IDbFill.FillFromReader(SqlDataReader reader, FieldMapperLoad map)
		{
			_cislo_poradace = (int)map.FillDataIntoField<int>("cislo_poradace", reader);
			_nazev = (string)map.FillDataIntoField<string>("nazev", reader);
			_bmp_name = (string)map.FillDataIntoField<string>("bmp_name", reader);
			_cislo_tridy = (int)map.FillDataIntoField<int>("cislo_tridy", reader);
			_druh = (string)map.FillDataIntoField<string>("druh", reader);
			_reference_poradace = (string)map.FillDataIntoField<string>("reference_poradace", reader);
			_obdobi = (SqlInt64)map.FillDataIntoField<SqlInt64>("obdobi", reader);
			_hrat_na_obdobi = (string)map.FillDataIntoField<string>("hrat_na_obdobi", reader);
			_priznak_hier = (string)map.FillDataIntoField<string>("priznak_hier", reader);
			_dyn_cg = (SqlInt16)map.FillDataIntoField<SqlInt16>("dyn_cg", reader);
			_dyn_ss = (SqlInt16)map.FillDataIntoField<SqlInt16>("dyn_ss", reader);
			_dyn_os = (SqlInt16)map.FillDataIntoField<SqlInt16>("dyn_os", reader);
			_archival = (string)map.FillDataIntoField<string>("archival", reader);
			_generate_reference = (string)map.FillDataIntoField<string>("generate_reference", reader);
			_maska = (string)map.FillDataIntoField<string>("maska", reader);
			return true;
		}
		/// <summary>
		/// Metoda, ve které datový objekt připraví podklady pro uložení svých dat do databáze.
		/// Objekt svoje proměnné vloží do exportní mapy prostřednictvím metod map.AddTable(); map.AddColumn();
		/// Pokud objekt chce plnit více tabulek, plní je do mapy postupně, vždy v pořadí {tabulka, sloupce tabulky; další tabulka; sloupce}.
		/// Po naplnění mapy se vrací true.
		/// </summary>
		/// <param name="map"></param>
		/// <returns></returns>
		bool IDbRecord.PrepareSaveData(FieldMapperSave map)
		{ return false; }
		#endregion
		#region Static generátor SQL selectu
		/// <summary>
		/// SQL SELECT pro načtení columnů, odpovídajících této struktuře. Pozor: neobsahuje filtr ani order.
		/// </summary>
		public static string SqlSelect { get { return @"SELECT cislo_poradace, nazev, bmp_name, cislo_tridy, druh, reference_poradace, obdobi, hrat_na_obdobi, priznak_hier, dyn_cg, dyn_ss, dyn_os, archival, generate_reference, maska FROM lcs.poradace"; } }
		#endregion
		#region Overrides
		/// <summary>
		/// Háček, který je zavolán po načtení dat.
		/// </summary>
		protected override void RetrieveAfter()
		{
			base.RetrieveAfter();
		}
		#endregion
        #region Vztahy z pořadačů, vztahy na pořadač
        /// <summary>
        /// Seznam všech vztahů z tohoto pořadače (odtud zleva někam doprava).
        /// </summary>
        public List<RelationInfo> RelationLeftList { get { return this._GetRelationLeftInfoList(); } }
        /// <summary>
        /// Seznam všech vztahů z tohoto pořadače (odtud zleva někam doprava).
        /// Vrací instance třídy RelationSideInfo, v níž je uložená navíc i strana vztahu (zde je strana Right, protože vztah ukazuje doprava).
        /// </summary>
        public List<RelationSideInfo> RelationSideLeftList { get { return this._GetRelationSideLeftInfoList(); } }
        /// <summary>
        /// Seznam všech vztahů, které vedou do tohoto pořadače (odkudsi zleva sem doprava).
        /// </summary>
        public List<RelationInfo> RelationTargetList { get { return this._GetRelationTargetInfoList(); } }
        /// <summary>
        /// Seznam všech vztahů do tohoto pořadače (odkudsi zleva sem doprava).
        /// Vrací instance třídy RelationSideInfo, v níž je uložená navíc i strana vztahu (zde je strana Left, protože vztah ukazuje doleva).
        /// </summary>
        public List<RelationSideInfo> RelationSideTargetList { get { return this._GetRelationSideTargetInfoList(); } }
        /// <summary>
        /// Vrátí seznam dat o vztazích tohoto pořadače (odtud zleva někam doprava).
        /// </summary>
        /// <returns></returns>
        private List<RelationInfo> _GetRelationLeftInfoList()
        {
            List<int> list = this._GetRelationLeftNumberList();
            return Repository.Relations.GetList(list);
        }
        /// <summary>
        /// Vrátí seznam dat o vztazích z tohoto pořadače (odtud zleva někam doprava).
        /// Vrací instance třídy RelationSideInfo, v níž je uložená navíc i strana vztahu (zde je strana Right, protože vztah ukazuje doprava).
        /// </summary>
        /// <returns></returns>
        private List<RelationSideInfo> _GetRelationSideLeftInfoList()
        {
            List<int> list = this._GetRelationLeftNumberList();
            return Repository.Relations.GetSideList(list, RelationSideType.Right);
        }
        /// <summary>
        /// Vrátí seznam dat o vztazích, které vedou do tohoto pořadače (odkudsi zleva sem doprava).
        /// </summary>
        /// <returns></returns>
        private List<RelationInfo> _GetRelationTargetInfoList()
        {
            List<int> list = this._GetRelationTargetNumberList();
            return Repository.Relations.GetList(list);
        }
        /// <summary>
        /// Vrátí seznam všech vztahů do tohoto pořadače (odkudsi zleva sem doprava).
        /// Vrací instance třídy RelationSideInfo, v níž je uložená navíc i strana vztahu (zde je strana Left, protože vztah ukazuje doleva).
        /// </summary>
        /// <returns></returns>
        private List<RelationSideInfo> _GetRelationSideTargetInfoList()
        {
            List<int> list = this._GetRelationTargetNumberList();
            return Repository.Relations.GetSideList(list, RelationSideType.Left);
        }
        /// <summary>
		/// Vrátí seznam čísel vztahů z tohoto pořadače.
        /// Pokud je načten, vrátí jej z paměti. Pokud není načten, načte jej, uloží do paměti a vrátí.
        /// Vrací pouze vztahy z pořadače, nikoli vztahy z třídy tohoto pořadače..
        /// Vztahy z třídy lze načíst přes třídu tohoto pořadače.
		/// </summary>
		private List<int> _GetRelationLeftNumberList()
		{
			List<int> result = this._RelationLeftNumberList;
			if (result == null)
			{
				lock (this._RLLocker)
				{
					if (this._RelationLeftNumberList == null)
					{
                        string sql = "SELECT cislo_vztahu FROM lcs.vztahy WHERE cislo_poradace = " + SqlFormat.ToSql(this.CisloPoradace) + " ORDER BY cislo_vztahu";
                        result = Db_Layer.GetList<int>(sql, this.ExternalDataConnector);
						this._RelationLeftNumberList = result;
					}
				}
			}
			return result;
		}
        /// <summary>
        /// Vrátí seznam čísel vztahů do tohoto pořadače.
        /// Pokud je načten, vrátí jej z paměti. Pokud není načten, načte jej, uloží do paměti a vrátí.
        /// </summary>
        private List<int> _GetRelationTargetNumberList()
        {
            List<int> result = this._RelationTargetNumberList;
            if (result == null)
            {
                lock (this._RRLocker)
                {
                    if (this._RelationTargetNumberList == null)
                    {
                        string sql = "SELECT distinct cislo_vztahu FROM lcs.vztahporadac WHERE cislo_poradace = " + SqlFormat.ToSql(this.CisloPoradace) + " ORDER BY cislo_vztahu";
                        result = Db_Layer.GetList<int>(sql, this.ExternalDataConnector);
                        this._RelationTargetNumberList = result;
                    }
                }
            }
            return result;
        }
        /// <summary>
		/// Úložiště seznamu čísel vztahů z tohoto pořadače
		/// </summary>
		private List<int> _RelationLeftNumberList;
        /// <summary>
        /// Úložiště seznamu čísel vztahů do tohoto pořadače
        /// </summary>
        private List<int> _RelationTargetNumberList;
        private object _RLLocker = new object();
        private object _RRLocker = new object();
        #endregion
		#region Rozšíření o další data
		/// <summary>
		/// Obsahuje (vrací) informace o třídě, jejíž data jsou uloženy v tomto pořadači.
		/// </summary>
		public ClassInfo ClassData { get { return Repository.Classes[this.CisloTridy]; } }
		///<summary>Generovat referenci lineárně? (true, pokud je GenerateReference == "A" a Maska není prázdná)</summary>
		public bool IsGenerateReference { get { return (!String.IsNullOrEmpty(this._generate_reference) && this._generate_reference == "A" && !String.IsNullOrEmpty(this._maska)); } }
		#endregion
		#region Generátor reference a názvu pro záznamy
		/// <summary>
		/// Vytvoří referenci a název pro další záznam.
		/// Nejprve si načte data z databáze, do paměti, a pak generuje data ze své paměti.
		/// </summary>
		/// <param name="refer"></param>
		/// <param name="name"></param>
		public string CreateNewReference()
		{
			if (!this.IsGenerateReference) return null;
			this._MaskaDetect();                   // Zajistí detekci masky
			return _CreateNewReference();
		}
		/// <summary>
		/// Na základě dat o detekované masce vygeneruje novou referenci.
		/// </summary>
		/// <returns></returns>
		private string _CreateNewReference()
		{
			lock (this.MaskaLock)
			{
				return _CreateNewReferenceLock();
			}
		}
		/// <summary>
		/// Na základě dat o detekované masce vygeneruje novou referenci.
		/// Zámek (this.MaskaLock) je zamčen.
		/// </summary>
		/// <returns></returns>
		private string _CreateNewReferenceLock()
		{
			string refer = this.MaskaFix;
			if (this.MaskaNumLength > 0)
			{
				int number = ++this.MaskaLastNumber;
				string refNum = number.ToString();
				if (refNum.Length < this.MaskaNumLength)
					refNum = refNum.PadLeft(this.MaskaNumLength, '0');
				refer = refer.Remove(this.MaskaNumBegin, this.MaskaNumLength);
				refer = refer.Insert(this.MaskaNumBegin, refNum);
			}
			return refer;
		}
		/// <summary>
		/// Zajistí detekci masky, jen při prvním volání.
		/// </summary>
		private void _MaskaDetect()
		{
			if (this.MaskaDetected) return;

			lock (this.MaskaLock)
			{
				if (!this.MaskaDetected)
					this._MaskaDetectLock();
			}
		}
		/// <summary>
		/// Detekuje masku.
		/// Zámek (this.MaskaLock) je zamčen.
		/// </summary>
		private void _MaskaDetectLock()
		{
			// Analýza masky:
			string maska = this.Maska;            // Například "PM200#####"
			string maskaFix = "";
			int maskaNumBegin = -1;
			int maskaNumLength = 0;
			int maskaStatus = 0;                  // Stav pozice: 0=nebyla proměná část, 1=právě je proměnná část, 2=byla proměnná část a po ní text
			for (int i = 0; i < maska.Length; i++)
			{
				string c = maska.Substring(i, 1);
				if (c == "#")
				{
					if (maskaStatus == 0)
					{
						maskaNumBegin = i;
						maskaStatus = 1;
					}
					if (maskaStatus == 1)
					{
						maskaNumLength++;
					}
					c = " ";
				}
				else
				{
					if (maskaStatus == 1)
						maskaStatus = 2;
				}
				maskaFix += c;
			}
			this.MaskaFix = maskaFix;
			this.MaskaNumBegin = maskaNumBegin;
			this.MaskaNumLength = maskaNumLength;

			// Analýza poslední známé reference, určení čísla:
			this.MaskaLastNumber = 0;
			string referLast = this._ReferLastLoad();
			if (referLast != null && referLast.Length >= maskaNumBegin + maskaNumLength)
			{
				int lastNum;
				if (Int32.TryParse(referLast.Substring(maskaNumBegin, maskaNumLength), out lastNum))
					this.MaskaLastNumber = lastNum;
			}

			// Potvrzení, že reference je načtena:
			this.MaskaDetected = true;
		}
		/// <summary>
		/// Načte poslední reálnou referenci z databáze
		/// </summary>
		/// <returns></returns>
		private string _ReferLastLoad()
		{
			ClassInfo classData = this.ClassData;
			if (classData == null) return String.Empty;
			string table = classData.GetTableName(classData.IsSubject ? ClassTableType.Subjekt : ClassTableType.Master);
			string sql = "SELECT TOP 1 reference_subjektu FROM " + table + " WHERE cislo_poradace = " + this.CisloPoradace.ToString() + " ORDER BY reference_subjektu DESC";
            string lastRefer = Db_Layer.GetItem<string>(sql, this.ExternalDataConnector);
			return (!String.IsNullOrEmpty(lastRefer) ? lastRefer : String.Empty);
		}
		protected object MaskaLock = new object();
		protected bool MaskaDetected;
		protected string MaskaFix;
		protected int MaskaNumBegin;
		protected int MaskaNumLength;
		protected int MaskaLastNumber;
		#endregion
	}
	#endregion
	#region CLASS RelationsCls + RelationsInfo
	/// <summary>
	/// Sada vztahů
	/// </summary>
	public class RelationsCls : RepositorySegmentCls<Int32, RelationInfo>
	{
		/// <summary>
		/// Konstruktor. Na vstupu očekává maximální počet záznamů, které může držet v paměti.
		/// Pokud by načítal další záznamy, pak nejstarší z paměti uvolní.
		/// </summary>
		/// <param name="maxItemCnt">Nejvyšší počet záznamů. -1 = neomezeně. 0 = žádný !!!</param>
		public RelationsCls(int maxItemCnt)
			: base(maxItemCnt)
		{ }
		/// <summary>
		/// Tato property vrátí SQL SELECT pro načtení jednoho záznamu s daty.
		/// SQL SELECT musí ve vhodném místě obsahovat token {{RecordNumber}}, na jehož místo jádro dosadí číslo hledaného záznamu nebo seznam čísel.
		/// Konkrétně, select by měl obsahovat frázi: "WHERE cislo_tridy {{RecordNumber}}", 
		/// jádro pak dosadí buď "WHERE cislo_tridy = 12345", 
		/// anebo dosadí "WHERE cislo_tridy in (1,2,3,4,5,6,7)", podle požadavku.
		/// Kdo nemá rád explicitní texty, určitě rád použije konstantu TOKEN_RECORD_NUMBER.
		/// </summary>
		protected override string SqlSelect
		{
			get
			{
				return RelationInfo.SqlSelect + " WHERE cislo_vztahu " + TOKEN_RECORD_NUMBER;
			}
		}
		/// <summary>
		/// Háček volaný po načtení záznamu z databáze.
		/// Háček se volá i když je přepsaná virtuální metoda this.GetDataItem(), je volán před háčkem DataItemAddBefore() / DataItemValidateBefore()
		/// </summary>
		/// <param name="item"></param>
		protected override void DataItemRetrieveAfter(RelationInfo item)
		{
			base.DataItemRetrieveAfter(item);
		}
        /// <summary>
        /// Vrátí seznam vztahů, které jsou dány jejich čísly.
        /// Vrací seznam objektů třídy RelationSideInfo, což je RelationInfo + RelationSideType.
        /// Jako stranu vztahů ukládá předanou hodnotu.
        /// </summary>
        /// <param name="list"></param>
        /// <param name="side"></param>
        /// <returns></returns>
        public List<RelationSideInfo> GetSideList(IEnumerable<int> list, RelationSideType side)
        {
            List<RelationSideInfo> result = new List<RelationSideInfo>();
            List<RelationInfo> relations = this.GetList(list, true);
            foreach (RelationInfo relation in relations)
                result.Add(new RelationSideInfo(relation, side));
            return result;
        }
    }
 	/// <summary>
	/// Jedna položka vztahu
	/// </summary>
	public class RelationInfo : RepositorySegmentItem<Int32>, IDbRecord
	{
		#region Abstract and overrides
		/// <summary>
		/// Klíčová hodnota záznamu. Potomek musí implementovat = namapovat na konkrétní property, která nese skutečný klíč záznamu.
		/// </summary>
		protected override int CurrentKeyValue { get { return this._cislo_vztahu; } set { this._cislo_vztahu = value; } }
		/// <summary>
		/// Číslo záznamu. Potomek musí implementovat = namapovat na konkrétní property, která nese skutečné číslo záznamu.
		/// </summary>
		// internal override Int32 CurrentRecordNumber { get { return this._cislo_vztahu; } protected set { this._cislo_vztahu = value; } }
		/// <summary>
		/// Vizualizace
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			return "Relation " + this.CisloVztahu.ToString() + ": " + this.Nazev;
		}
        /// <summary>
        /// Název z dané strany
        /// </summary>
        /// <param name="side"></param>
        /// <returns></returns>
        public string TextFromSide(RelationSideType side)
        {
            return "Relation " + this.CisloVztahu.ToString() + ": " + this.NameFromSide(side);
        }
        /// <summary>
        /// Název z dané strany včetně možnosti reverzace
        /// </summary>
        /// <param name="side"></param>
        /// <returns></returns>
        public string TextFromSide(RelationSideType originalSide, bool reverseSide)
        {
            return "Relation " + this.CisloVztahu.ToString() + ": " + this.NameFromSide(originalSide, reverseSide);
        }
        #endregion
		#region Public data property
		///<summary><para>Atribut: Číslo vztahu</para><para>Db: lcs.vztahy.cislo_vztahu (int not null)</para></summary>
		public int CisloVztahu { get { return _cislo_vztahu; } }
		///<summary><para>Vztah 6265: Třída (zprava: Vztahy)</para><para>Db: lcs.vztahy.cislo_tridy (int null)</para></summary>
		public SqlInt32 CisloTridy { get { return _cislo_tridy; } }
		///<summary><para>Vztah 6266: Pořadač (zprava: Vztahy)</para><para>Db: lcs.vztahy.cislo_poradace (int null)</para></summary>
		public SqlInt32 CisloPoradace { get { return _cislo_poradace; } }
		///<summary><para>Atribut: Druh (T,N)</para><para>Db: lcs.vztahy.druh (char (1) null)</para></summary>
		public string Druh { get { return _druh; } }
		///<summary><para>Atribut: Typ vztahu [vztahy_typ] {"SS"=Subjekt - Subjekt; "SN"=Subjekt - Nonsubjekt; "OS"=Položka - Subjekt; "ON"=Položka - Nonsubjekt; "NS"=Nonsubjekt - Subjekt; "NN"=Nonsubjekt - Nonsubjekt}</para><para>Db: lcs.vztahy.typ (char (2) not null)</para></summary>
		public string Typ { get { return _typ; } }
		///<summary><para>Atribut: Druh vztahu [vztahy_statdyn] {"S"=Statický; "D"=Dynamický}</para><para>Db: lcs.vztahy.statdyn (char (1) not null)</para></summary>
		public string Statdyn { get { return _statdyn; } }
		///<summary><para>Atribut: Název zleva</para><para>Db: lcs.vztahy.nazev (varchar (40) not null)</para></summary>
		public string Nazev { get { return _nazev; } }
		///<summary><para>Atribut: Název zprava</para><para>Db: lcs.vztahy.nazev_zprava (varchar (40) null)</para></summary>
		public string NazevZprava { get { return _nazev_zprava; } }
		///<summary><para>Atribut: Kardinalita zleva [pocetnost] {"1"=Jednou; "N"=Mnohokrát}</para><para>Db: lcs.vztahy.pocetnost_left (char (1) null)</para></summary>
		public string PocetnostLeft { get { return _pocetnost_left; } }
		///<summary><para>Atribut: Kardinalita zprava [pocetnost] {"1"=Jednou; "N"=Mnohokrát}</para><para>Db: lcs.vztahy.pocetnost_right (char (1) null)</para></summary>
		public string PocetnostRight { get { return _pocetnost_right; } }
		///<summary><para>Atribut: Nutnost zadání [typ_ano_ne] {"A"=Ano; "N"=Ne}</para><para>Db: lcs.vztahy.nutnost_zadani (char (1) null)</para></summary>
		public string NutnostZadani { get { return _nutnost_zadani; } }
		///<summary><para>Atribut: Přenášet při nové položce</para><para>Db: lcs.vztahy.prenositelnost (char (1) null)</para></summary>
		public string Prenositelnost { get { return _prenositelnost; } }
		///<summary><para>Atribut: Dbname</para><para>Db: lcs.vztahy.column_name (varchar (60) null)</para></summary>
		public string ColumnName { get { return _column_name; } }
		///<summary><para>Atribut: Pořadí</para><para>Db: lcs.vztahy.poradi (smallint null)</para></summary>
		public SqlInt16 Poradi { get { return _poradi; } }
        ///<summary><para>Atribut: Identifkace pro transf. zleva</para><para>Db: lcs.vztahy.transformace_l (varchar (50) null)</para></summary>
        public string TransformaceL { get { return _transformace_l; } }
        ///<summary><para>Atribut: Identifkace pro transf. zprava</para><para>Db: lcs.vztahy.transformace_r (varchar (50) null)</para></summary>
        public string TransformaceR { get { return _transformace_r; } }
        ///<summary><para>Db: lcs.vztahy.isvisible (varchar (1) not null)</para></summary>
		public string Isvisible { get { return _isvisible; } }
		#endregion
		#region Protected data fields
		#pragma warning disable 1591
		protected int _cislo_vztahu;
		protected SqlInt32 _cislo_tridy;
		protected SqlInt32 _cislo_poradace;
		protected string _druh;
		protected string _typ;
		protected string _statdyn;
		protected string _nazev;
		protected string _nazev_zprava;
		protected string _pocetnost_left;
		protected string _pocetnost_right;
		protected string _nutnost_zadani;
		protected string _prenositelnost;
		protected string _column_name;
		protected SqlInt16 _poradi;
        protected string _transformace_l;
        protected string _transformace_r;
        protected string _isvisible;
		#pragma warning restore 1591
		#endregion
		#region IDbRecord
		int IDbRecord.RecordNumber { get; set; }
		/// <summary>
		/// Metoda, která umožní rychle naplnit záznam daty z přicházejícího datareaderu.
		/// Typové čtení zajišťuje mapa, metodou map.GetItem...(string columnName).
		/// Metoda má vracet true = data byla skutečně načtena a do záznamu uložena (false = nedošlo k tomu, data se budou načítat genericky).
		/// </summary>
		/// <param name="reader"></param>
		/// <param name="map"></param>
		/// <returns></returns>
		bool IDbFill.FillFromReader(SqlDataReader reader, FieldMapperLoad map)
		{
			_cislo_vztahu = (int)map.FillDataIntoField<int>("cislo_vztahu", reader);
			_cislo_tridy = (SqlInt32)map.FillDataIntoField<SqlInt32>("cislo_tridy", reader);
			_druh = (string)map.FillDataIntoField<string>("druh", reader);
			_typ = (string)map.FillDataIntoField<string>("typ", reader);
			_statdyn = (string)map.FillDataIntoField<string>("statdyn", reader);
			_nazev = (string)map.FillDataIntoField<string>("nazev", reader);
			_nazev_zprava = (string)map.FillDataIntoField<string>("nazev_zprava", reader);
			_pocetnost_left = (string)map.FillDataIntoField<string>("pocetnost_left", reader);
			_pocetnost_right = (string)map.FillDataIntoField<string>("pocetnost_right", reader);
			_nutnost_zadani = (string)map.FillDataIntoField<string>("nutnost_zadani", reader);
			_prenositelnost = (string)map.FillDataIntoField<string>("prenositelnost", reader);
			_column_name = (string)map.FillDataIntoField<string>("column_name", reader);
			_poradi = (SqlInt16)map.FillDataIntoField<SqlInt16>("poradi", reader);
			_transformace_l = (string)map.FillDataIntoField<string>("transformace_l", reader);
			_transformace_r = (string)map.FillDataIntoField<string>("transformace_r", reader);
			_isvisible = (string)map.FillDataIntoField<string>("isvisible", reader);
			return true;
		}
		/// <summary>
		/// Metoda, ve které datový objekt připraví podklady pro uložení svých dat do databáze.
		/// Objekt svoje proměnné vloží do exportní mapy prostřednictvím metod map.AddTable(); map.AddColumn();
		/// Pokud objekt chce plnit více tabulek, plní je do mapy postupně, vždy v pořadí {tabulka, sloupce tabulky; další tabulka; sloupce}.
		/// Po naplnění mapy se vrací true.
		/// </summary>
		/// <param name="map"></param>
		/// <returns></returns>
		bool IDbRecord.PrepareSaveData(FieldMapperSave map)
		{ return false; }
		#endregion
		#region Static generátor SQL selectu
		/// <summary>
		/// SQL SELECT pro načtení columnů, odpovídajících této struktuře. Pozor: neobsahuje filtr ani order.
		/// </summary>
		public static string SqlSelect { get { return @"SELECT cislo_vztahu, cislo_tridy, cislo_poradace, druh, typ, statdyn, nazev, nazev_zprava, pocetnost_left, pocetnost_right, nutnost_zadani, prenositelnost, column_name, poradi, transformace_l, transformace_r, isvisible FROM lcs.vztahy"; } }
		#endregion
		#region Overrides
		/// <summary>
		/// Háček, který je zavolán po načtení dat.
		/// </summary>
		protected override void RetrieveAfter()
		{
			
		}
		#endregion
        #region Typové property
        ///<summary>Typový Atribut: Typ vztahu {"SS"=Subjekt - Subjekt; "SN"=Subjekt - Nonsubjekt; "OS"=Položka - Subjekt; "ON"=Položka - Nonsubjekt; "NS"=Nonsubjekt - Subjekt; "NN"=Nonsubjekt - Nonsubjekt}</summary>
		public RelationTypType RelationTyp { get { return ConvertStringToRelationTyp(_typ); } }
		///<summary>Typový Atribut: Druh vztahu {Statický; Dynamický}</summary>
		public RelationStatDynType RelationStatDyn { get { return ConvertStringToRelationStatDyn(_statdyn); } }
		#endregion
		#region Konverze enumů typických pro vztah
		/// <summary>
		/// Vrátí stranu vztahu (Left, Right, None) ze stringu L,R,x
		/// </summary>
		/// <returns></returns>
		public static RelationSideType ConvertStringToRelationSide(string strana)
		{
			if (String.IsNullOrEmpty(strana)) return RelationSideType.None;
			if (strana == "L") return RelationSideType.Left;
			if (strana == "R") return RelationSideType.Right;
			return RelationSideType.None;
		}
		/// <summary>
		/// Vrátí string (L,R,x) ze strany vztahu (Left, Right, None)
		/// </summary>
		/// <returns></returns>
		public static string ConvertRelationSideToString(RelationSideType side)
		{
			switch (side)
			{
				case RelationSideType.Left: return "L";
				case RelationSideType.Right: return "R";
			}
			return "x";
		}
		/// <summary>
		/// Vrátí stranu vztahu
		/// </summary>
		/// <returns></returns>
		public static RelationTypType ConvertStringToRelationTyp(string typ)
		{
			if (typ.IsEmpty()) return RelationTypType.None;
			switch (typ.AllTrim())
			{
				case "SS": return RelationTypType.SubjectSubject;
				case "SN": return RelationTypType.SubjectNonsubject;
				case "OS": return RelationTypType.ObjectSubject;
				case "ON": return RelationTypType.ObjectNonsubject;
				case "NS": return RelationTypType.NonsubjectSubject;
				case "NN": return RelationTypType.NonsubjectNonsubject;
			}
			return RelationTypType.None;
		}
		/// <summary>
		/// Vrátí stranu vztahu
		/// </summary>
		/// <returns></returns>
		public static RelationStatDynType ConvertStringToRelationStatDyn(string statDyn)
		{
			if (statDyn.IsEmpty()) return RelationStatDynType.None;
			switch (statDyn.AllTrim())
			{
				case "S": return RelationStatDynType.Static;
				case "D": return RelationStatDynType.Dynamic;
			}
			return RelationStatDynType.None;
		}
		#endregion
		#region Rozšíření o další data
		/// <summary>
		/// Obsahuje (vrací) informace o třídě, která je zdrojem vztahu (nalevo).
		/// Pokud je vztah definován z pořadače, vrací null.
		/// </summary>
		public ClassInfo SourceClassData { get { return (this.CisloTridy.IsNull ? null : Repository.Classes[this.CisloTridy.Value]); } }
		/// <summary>
		/// Obsahuje (vrací) informace o pořadači, který je zdrojem vztahu (nalevo).
		/// Pokud je vztah definován ze třídy, vrací null.
		/// </summary>
		public FolderInfo SourceFolderData { get { return (this.CisloPoradace.IsNull ? null : Repository.Folders[this.CisloPoradace.Value]); } }
        /// <summary>
        /// Obsahuje (vrací) informace o třídě, která je zdrojem vztahu (nalevo).
        /// Pokud je vztah definován z pořadače, pak dohledá třídu pořadače a vrací informace o jeho třídě.
        /// Tím se liší od property SourceClassData, která pro vztahy deklarované z pořadače obsahuje null.
        /// </summary>
        public ClassInfo LeftClassInfo
        { 
            get 
            {
                if (!this.CisloPoradace.IsNull)
                {
                    FolderInfo folderInfo = this.SourceFolderData;
                    if (folderInfo != null)
                        return folderInfo.ClassData;
                    return null;
                }
                if (!this.CisloTridy.IsNull)
                    return this.SourceClassData;

                return null;
            }
        }
		/// <summary>
		/// Seznam pořadačů, do nichž (doprava) se může vázat tento vztah.
		/// </summary>
		public List<FolderInfo> FoldersList { get { return _GetFoldersList(); } }
		/// <summary>
		/// Obsahuje (vrátí) info o pořadači, který je uveden jako cílový pořadač pro tento vztah, s nejnižším číslem pořadače.
		/// </summary>
		public FolderInfo FolderFirst { get { return _GetFolderFirst(); } }
        /// <summary>
        /// Obsahuje (vrátí) seznam info o cílových třídách vztahu = distinct(ClassInfo) from FoldersList.
        /// pokud by některý pořadač odkazoval na nedostupnou třídu, nebude zde třída uvedena.
        /// </summary>
        public List<ClassInfo> TargetClasses { get { return _GetTargetClasses(); } }
		/// <summary>
		/// Metoda vrátí seznam pořadačů, které jsou uvedeny v seznamu this.VztahporadacList.
		/// </summary>
		/// <returns></returns>
		private List<FolderInfo> _GetFoldersList()
		{
			List<int> folders = this.VztahporadacList.ConvertAll<int>(vp => vp.CisloPoradace);
			return Repository.Folders.GetList(folders);
		}
		/// <summary>
		/// Seznam položek vztah - pořadač (bez dat pořadačů, jen klíč)
		/// </summary>
		private List<VztahporadacCls> VztahporadacList
		{
			get
			{
				if (this._VztahporadacList == null)
				{
					string sql = VztahporadacCls.SqlSelect + " WHERE cislo_vztahu = " + SqlFormat.ToSql(this._cislo_vztahu);
                    List<VztahporadacCls> vpList = Db_Layer.GetList<VztahporadacCls>(sql, this.ExternalDataConnector);
					vpList.Sort((a, b) => a.CisloPoradace.CompareTo(b.CisloPoradace));
					this._VztahporadacList = vpList;
				}
				return this._VztahporadacList;
			}
		}
		private List<VztahporadacCls> _VztahporadacList;
		/// <summary>
		/// Vrátí informace o prvním pořadači (s nejnižším číslem) pro tento vztah
		/// </summary>
		/// <returns></returns>
		private FolderInfo _GetFolderFirst()
		{
			List<VztahporadacCls> vpList = this.VztahporadacList;
			if (vpList.Count == 0) return null;
			return Repository.Folders[vpList[0].CisloPoradace];
		}
        /// <summary>
        /// Vrátí seznam info o cílových třídách vztahu = distinct(ClassInfo) from FoldersList
        /// </summary>
        /// <returns></returns>
        private List<ClassInfo> _GetTargetClasses()
        {
            Dictionary<int, ClassInfo> classes = new Dictionary<int, ClassInfo>();
            List<FolderInfo> foldersList = this.FoldersList;
            foreach (FolderInfo folder in foldersList)
            {
                ClassInfo classInfo = folder.ClassData;
                if (classInfo != null && !classes.ContainsKey(folder.CisloTridy))
                    classes.Add(folder.CisloTridy, classInfo);
            }
            return new List<ClassInfo>(classes.Values);
        }
        /// <summary>
        /// Vrátí název vztahu z dané strany.
        /// </summary>
        /// <param name="relationSide">Strana výchozí</param>
        /// <returns></returns>
        public string NameFromSide(RelationSideType relationSide)
        {
            return this.NameFromSide(relationSide, false);
        }
        /// <summary>
        /// Vrátí název vztahu z dané strany s možností reverze.
        /// Proč to:
        /// Pokud máme vztah, kde naše třída je Vpravo (přičemž Side je v nějaké proměnné!), tak můžeme chtít zjistit název vztahu "z druhé strany".
        /// Pak buď můžeme vztah ručně reverzovat, anebo zavolat NameFromSide(side, true) = vrátí název vztahu z druhé strany.
        /// </summary>
        /// <param name="relationSide">Strana výchozí</param>
        /// <param name="reverse">Požadavek na reverzaci strany</param>
        /// <returns></returns>
        public string NameFromSide(RelationSideType relationSide, bool reverse)
        {
            string nazev = (String.IsNullOrEmpty(this.Nazev) ? this.CisloVztahu.ToString() : this.Nazev);
            if ((relationSide == RelationSideType.Left && !reverse) ||
                (relationSide == RelationSideType.Right && reverse))
                return nazev;
            else if ((relationSide == RelationSideType.Right && !reverse) ||
                (relationSide == RelationSideType.Left && reverse))
                return (String.IsNullOrEmpty(this.NazevZprava) ? "(" + nazev + ")" : this.NazevZprava);
            return nazev;
        }
        /// <summary>
        /// Vrátí identifikaci vztahu pro transformaci, z dané strany.
        /// </summary>
        /// <param name="relationSide">Strana výchozí</param>
        /// <returns></returns>
        public string TransformFromSide(RelationSideType relationSide)
        {
            return this.TransformFromSide(relationSide, false);
        }
        /// <summary>
        /// Vrátí identifikaci vztahu pro transformaci, z dané strany.
        /// Proč to:
        /// Pokud máme vztah, kde naše třída je Vpravo (přičemž Side je v nějaké proměnné!), tak můžeme chtít zjistit název pro transformaci vztahu "z druhé strany".
        /// Pak buď můžeme vztah ručně reverzovat, anebo zavolat TransformFromSide(side, true) = vrátí název pro transformaci vztahu z druhé strany.
        /// </summary>
        /// <param name="relationSide">Strana výchozí</param>
        /// <param name="reverse">Požadavek na reverzaci strany</param>
        /// <returns></returns>
        public string TransformFromSide(RelationSideType relationSide, bool reverse)
        {
            if ((relationSide == RelationSideType.Left && !reverse) ||
                (relationSide == RelationSideType.Right && reverse))
                return this.TransformaceL;
            else if ((relationSide == RelationSideType.Right && !reverse) ||
                (relationSide == RelationSideType.Left && reverse))
                return this.TransformaceR;
            return this.Nazev;
        }
        /// <summary>
		/// Holý databázový sloupec statického vztahu, bez prefixu (bez tabulky).
        /// Vychází z this.ColumnName, který ale obsahuje db sloupec včetně prefixu a tabulky.
		/// Pro dynamické vztahy vrací null.
        /// </summary>
        public string DbColumn
        {
            get
            {
				if (this.RelationStatDyn != RelationStatDynType.Static) return null;
                if (this._DbColumn == null)
                {
                    string dbColumn = "";
                    string columnName = this.ColumnName;
                    if (!String.IsNullOrEmpty(columnName))
                    {
                        int index = columnName.LastIndexOf('.');
                        if (index >= 0 && index < (columnName.Length - 1))
                            dbColumn = columnName.Substring(index + 1).Trim();
                    }
                    this._DbColumn = dbColumn;
                }
                return this._DbColumn;
            }
        }
        private string _DbColumn;
		/// <summary>
		/// Název tabulky statického vztahu.
		/// Vrací typicky "lcs.product_order".
		/// Vychází z this.ColumnName, z něhož vrací text před poslední tečkou.
		/// Pro dynamické vztahy vrací null.
		/// </summary>
		public string TableName
		{
            get
            {
                if (this.RelationStatDyn != RelationStatDynType.Static) return null;
                if (this._TableName == null)
                {
                    string tableName = "";
                    string columnName = this.ColumnName;
                    if (!String.IsNullOrEmpty(columnName))
                    {
                        int index = columnName.LastIndexOf('.');
                        if (index > 0)
                            tableName = columnName.Substring(0, index).Replace(" ", "");
                    }
                    this._TableName = tableName;
                }
                return this._TableName;
            }
		}
        private string _TableName;
        /// <summary>
        /// Typ tabulky this.TableName.
        /// Vychází z this.ColumnName, z něhož načte název tabulky = text před poslední tečkou.
        /// Z názvu tabulky určí její typ a ten vrátí.
        /// Pro dynamické vztahy vrací None.
        /// </summary>
        public ClassTableType TableType
        {
            get
            {
                string tableName = this.TableName;
                if (String.IsNullOrEmpty(tableName)) return ClassTableType.None;
                return this.LeftClassInfo.GetTableType(tableName);
            }
        }
        /// <summary>
        /// Obsahuje true, pokud tento vztah je z hlavičky (this.RelationTyp je některý z : { SubjectSubject, SubjectNonsubject, NonsubjectSubject, NonsubjectNonsubject } )
        /// </summary>
        public bool IsMaster
        {
            get
            {
                return (this.RelationTyp == RelationTypType.SubjectSubject || this.RelationTyp == RelationTypType.SubjectNonsubject ||
                        this.RelationTyp == RelationTypType.NonsubjectSubject || this.RelationTyp == RelationTypType.NonsubjectNonsubject);
            }
        }
        /// <summary>
        /// Obsahuje true, pokud tento vztah je z položky (this.RelationTyp je některý z : { ObjectSubject, ObjectNonsubject } )
        /// </summary>
        public bool IsEntry
        {
            get
            {
                return (this.RelationTyp == RelationTypType.ObjectSubject || this.RelationTyp == RelationTypType.ObjectNonsubject);
            }
        }
        #endregion
        #region Komparátory
        /// <summary>
        /// Porovná dva záznamy dle názvu (Name)
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static int CompareByName(RelationInfo a, RelationInfo b)
        {
            if (a == null && b == null) return 0;
            if (a == null) return -1;
            if (b == null) return 1;
            return String.Compare(a.Nazev, b.Nazev);
        }
        /// <summary>
        /// Porovná dva záznamy dle typu vztahu, a pak dle názvu (Name).
        /// Podle typu řadí vztahy v tomto pořadí: hlavičkové (statické i dynamické dohromady), a pak položkové (statické i dynamické opět dohromady).
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static int CompareByTypeName(RelationInfo a, RelationInfo b)
        {
            if (a == null && b == null) return 0;
            if (a == null) return -1;
            if (b == null) return 1;
            
            // Typ: Master - Entry - neurčitelné:
            int at = (a.IsMaster ? 1 : (a.IsEntry ? 2 : 3));
            int bt = (b.IsMaster ? 1 : (b.IsEntry ? 2 : 3));
            if (at != bt) return at.CompareTo(bt);

            // Název:
            return String.Compare(a.Nazev, b.Nazev);
        }
        #endregion
    }
    /// <summary>
    /// Vztah plus strana vztahu
    /// </summary>
    public class RelationSideInfo
    {
        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="relationInfo"></param>
        /// <param name="side"></param>
        public RelationSideInfo(RelationInfo relationInfo, RelationSideType side)
        {
            if (relationInfo == null)
                throw new SysException("Konstruktor třídy RelationSideInfo vyžaduje hodnotu RelationInfo not null.");
            this.RelationInfo = relationInfo;
            this.Side = side;
        }
        /// <summary>
        /// Vizualizace
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return this.Side.ToString() + ": " + this.RelationInfo.TextFromSide(this.Side);
        }
        /// <summary>
        /// Informace o vztahu.
        /// </summary>
        public RelationInfo RelationInfo { get; private set; }
        /// <summary>
        /// Strana:
        /// Right: v této situaci je ten, kdo se ptá, ten vlevo ve vztahu (například hlavička příjemky), a vztah ukazuje doprava (například na sklad).
        /// Left : v této situaci je ten, kdo se ptá, ten vpravo ve vztahu (například kmenová karta zboží), a vztah ukazuje "zpátky" doleva (například na položku příjemky).
        /// </summary>
        public RelationSideType Side { get; private set; }

        ///<summary><para>Atribut: Číslo vztahu</para><para>Db: lcs.vztahy.cislo_vztahu (int not null)</para></summary>
        public int CisloVztahu { get { return this.RelationInfo.CisloVztahu; } }
        #region Komparátory
        /// <summary>
        /// Porovná dva záznamy dle názvu (Name)
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static int CompareByName(RelationSideInfo a, RelationSideInfo b)
        {
            if (a == null && b == null) return 0;
            if (a == null) return -1;
            if (b == null) return 1;
            return String.Compare(a.RelationInfo.Nazev, b.RelationInfo.Nazev);
        }
        /// <summary>
        /// Porovná dva záznamy dle typu vztahu, a pak dle názvu (Name).
        /// Podle typu řadí vztahy v tomto pořadí: hlavičkové (statické i dynamické dohromady), a pak položkové (statické i dynamické opět dohromady).
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static int CompareByTypeName(RelationSideInfo a, RelationSideInfo b)
        {
            if (a == null && b == null) return 0;
            if (a == null) return -1;
            if (b == null) return 1;

            // Typ: Master - Entry - neurčitelné:
            int at = (a.RelationInfo.IsMaster ? 1 : (a.RelationInfo.IsEntry ? 2 : 3));
            int bt = (b.RelationInfo.IsMaster ? 1 : (b.RelationInfo.IsEntry ? 2 : 3));
            if (at != bt) return at.CompareTo(bt);

            // Název:
            string an = a.RelationInfo.NameFromSide(a.Side);
            string bn = b.RelationInfo.NameFromSide(b.Side);
            return String.Compare(an, bn);
        }
        #endregion
    }
	#region CLASS VztahporadacCls : Třída odvozená z tabulky lcs.vztahporadac
	/// <summary>
	/// VztahporadacCls : Data z Master tabulky třídy 794: Vztah - pořadač (RelationFolderInst), Nonsubjektová
	/// Data načtena z tabulky lcs.vztahporadac
	/// </summary>
	public partial class VztahporadacCls : IDbRecord
	{
		#region Public systém property
		/// <summary>Číslo záznamu = cislo_nonsubjektu</summary>
		public int RecordNumber { get { return this._cislo_nonsubjektu; } }
		#endregion
		#region Public data property
		///<summary><para>Atribut: Číslo non subjektu</para><para>Db: lcs.vztahporadac.cislo_nonsubjektu (int not null)</para></summary>
		public int CisloNonsubjektu { get { return _cislo_nonsubjektu; } }
		///<summary><para>Vztah 6267: Vztah (zprava: Vztah pořadač)</para><para>Db: lcs.vztahporadac.cislo_vztahu (int not null)</para></summary>
		public int CisloVztahu { get { return _cislo_vztahu; } }
		///<summary><para>Vztah 6268: Pořadač (zprava: Vztah pořadač)</para><para>Db: lcs.vztahporadac.cislo_poradace (int not null)</para></summary>
		public int CisloPoradace { get { return _cislo_poradace; } }
		#endregion
		#region Protected data fields
		#pragma warning disable 1591
		protected int _cislo_nonsubjektu;
		protected int _cislo_vztahu;
		protected int _cislo_poradace;
		#pragma warning restore 1591
		#endregion
		#region IDbRecord
		int IDbRecord.RecordNumber { get; set; }
		/// <summary>
		/// Metoda, která umožní rychle naplnit záznam daty z přicházejícího datareaderu.
		/// Typové čtení zajišťuje mapa, metodou map.GetItem...(string columnName).
		/// Metoda má vracet true = data byla skutečně načtena a do záznamu uložena (false = nedošlo k tomu, data se budou načítat genericky).
		/// </summary>
		/// <param name="reader"></param>
		/// <param name="map"></param>
		/// <returns></returns>
		bool IDbFill.FillFromReader(SqlDataReader reader, FieldMapperLoad map)
		{
			_cislo_nonsubjektu = (int)map.FillDataIntoField<int>("cislo_nonsubjektu", reader);
			_cislo_vztahu = (int)map.FillDataIntoField<int>("cislo_vztahu", reader);
			_cislo_poradace = (int)map.FillDataIntoField<int>("cislo_poradace", reader);
			return true;
		}
		/// <summary>
		/// Metoda, ve které datový objekt připraví podklady pro uložení svých dat do databáze.
		/// Objekt svoje proměnné vloží do exportní mapy prostřednictvím metod map.AddTable(); map.AddColumn();
		/// Pokud objekt chce plnit více tabulek, plní je do mapy postupně, vždy v pořadí {tabulka, sloupce tabulky; další tabulka; sloupce}.
		/// Po naplnění mapy se vrací true.
		/// </summary>
		/// <param name="map"></param>
		/// <returns></returns>
		bool IDbRecord.PrepareSaveData(FieldMapperSave map)
		{ return false; }
		#endregion
		#region Static generátor SQL selectu
		/// <summary>
		/// SQL SELECT pro načtení columnů, odpovídajících této struktuře. Pozor: neobsahuje filtr ani order.
		/// </summary>
		public static string SqlSelect { get { return @"SELECT * FROM lcs.vztahporadac"; } }
		#endregion
	}
	#endregion
	/// <summary>
	/// Strana vztahu
	/// </summary>
	public enum RelationSideType
	{
        /// <summary>Strana neurčena</summary>
		None = 1,
        /// <summary>Strana vlevo</summary>
		Left,
        /// <summary>Strana vpravo</summary>
		Right
	}
	/// <summary>
	/// Typ vztahu (určuje, co stojí vlevo a co stojí vpravo: subjekt, objekt, nonsubjekt)
	/// </summary>
	public enum RelationTypType
	{
		None = 1,
		SubjectSubject,
		SubjectNonsubject,
		ObjectSubject,
		ObjectNonsubject,
		NonsubjectSubject,
		NonsubjectNonsubject
	}
	/// <summary>
	/// Konstrukce vztahu (statický / dynamický)
	/// </summary>
	public enum RelationStatDynType
	{
		None = 1,
		Static,
		Dynamic
	}
	#endregion
	#region CLASS FiltersCls + FilterInfo ( + NisFilterCls + FilterPainterCls)
	/// <summary>
	/// Sada vztahů
	/// </summary>
	public partial class FiltersCls : RepositorySegmentCls<Int32, FilterInfo>
	{
		/// <summary>
		/// Konstruktor. Na vstupu očekává maximální počet záznamů, které může držet v paměti.
		/// Pokud by načítal další záznamy, pak nejstarší z paměti uvolní.
		/// </summary>
		/// <param name="maxItemCnt">Nejvyšší počet záznamů. -1 = neomezeně. 0 = žádný !!!</param>
		public FiltersCls(int maxItemCnt)
			: base(maxItemCnt)
		{ }
		/// <summary>
		/// Tato property vrátí SQL SELECT pro načtení jednoho záznamu s daty.
		/// SQL SELECT musí ve vhodném místě obsahovat token {{RecordNumber}}, na jehož místo jádro dosadí číslo hledaného záznamu nebo seznam čísel.
		/// Konkrétně, select by měl obsahovat frázi: "WHERE cislo_tridy {{RecordNumber}}", 
		/// jádro pak dosadí buď "WHERE cislo_tridy = 12345", 
		/// anebo dosadí "WHERE cislo_tridy in (1,2,3,4,5,6,7)", podle požadavku.
		/// Kdo nemá rád explicitní texty, určitě rád použije konstantu TOKEN_RECORD_NUMBER.
		/// </summary>
		protected override string SqlSelect
		{
			get
			{
				return FilterInfo.SqlSelect + " WHERE cislo_filtru " + TOKEN_RECORD_NUMBER;
			}
		}
		/// <summary>
		/// Háček volaný po načtení záznamu z databáze.
		/// Háček se volá i když je přepsaná virtuální metoda this.GetDataItem(), je volán před háčkem DataItemAddBefore() / DataItemValidateBefore()
		/// </summary>
		/// <param name="item"></param>
		protected override void DataItemRetrieveAfter(FilterInfo item)
		{
			base.DataItemRetrieveAfter(item);
		}
        /// <summary>
        /// Načte a vrátí položky odpovídající filtrům dle daného filtru
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        protected override IEnumerable<RepositoryTextItem<int>> LoadAllTexts(string where)
        {
            string sql = "SELECT cislo_filtru as item_key, nazev as text FROM lcs.filters" + (where == null ? "" : " WHERE " + where) + " ORDER BY nazev";
            DataConnector connector = GetRepositoryConnector();
            List<RepositoryTextItem<int>> list = Db_Layer.GetList<RepositoryTextItem<int>>(sql);
            return list;
        }
    }
	/// <summary>
	/// Jeden konkrétní filtr
	/// </summary>
	public partial class FilterInfo : RepositorySegmentItem<Int32>, IDbRecord
	{
		#region Abstract and overrides
		/// <summary>
		/// Klíčová hodnota záznamu. Potomek musí implementovat = namapovat na konkrétní property, která nese skutečný klíč záznamu.
		/// </summary>
		protected override int CurrentKeyValue { get { return this._cislo_filtru; } set { this._cislo_filtru = value; } }
		/// <summary>
		/// Číslo záznamu. Potomek musí implementovat = namapovat na konkrétní property, která nese skutečné číslo záznamu.
		/// </summary>
		// public override Int32 CurrentRecordNumber { get { return this._cislo_filtru; } protected set { this._cislo_filtru = value; } }
		/// <summary>
		/// Vizualizace
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			return "Filter " + this.CisloFiltru.ToString() + ": " + this.Nazev;
		}
		/// <summary>
		/// Číslo filtru: Název filtru
		/// </summary>
		public virtual string ReferNazev
		{ get { return this.CisloFiltru.ToString() + ": " + this.Nazev; } }
		#endregion
		#region Public data property
		///<summary><para>Atribut: Číslo filtru</para><para>Db: lcs.filters.cislo_filtru (int not null)</para></summary>
		public int CisloFiltru { get { return _cislo_filtru; } }
		///<summary><para>Atribut: Název</para><para>Db: lcs.filters.nazev (varchar (40) not null)</para></summary>
		public string Nazev { get { return _nazev; } }
		///<summary><para>Atribut: Třída</para><para>Db: lcs.filters.cislo_tridy (int not null)</para></summary>
		public int CisloTridy { get { return _cislo_tridy; } }
		///<summary><para>Atribut: Definice</para><para>Db: lcs.filters.sort_string (varchar (255) null)</para></summary>
		public string SortString { get { return _sort_string; } }
		///<summary><para>Vztah 6647: Privátní pro (zprava: Privátní filtry)</para><para>Db: lcs.filters.zam_id (int not null)</para></summary>
		public int ZamId { get { return _zam_id; } }
		///<summary><para>Atribut: Brát celou třídu [typ_ano_ne] {"A"=Ano; "N"=Ne}</para><para>Db: lcs.filters.celou_tridu (char (1) null)</para></summary>
		public string CelouTridu { get { return _celou_tridu; } }
		///<summary><para>Atribut: Rozsah platnosti [trida_nebo_poradac] {"T"=Třída; "P"=Pořadač}</para><para>Db: lcs.filters.rozsah_platnosti (char (1) null)</para></summary>
		public string RozsahPlatnosti { get { return _rozsah_platnosti; } }
		///<summary><para>Atribut: Seznam pořadačů</para><para>Db: lcs.filters.seznam_poradacu (varchar (-1) null)</para></summary>
		public string SeznamPoradacu { get { return _seznam_poradacu; } }
		///<summary><para>Atribut: Uživatelský popis filtru</para><para>Db: lcs.filters.popis (varchar (255) null)</para></summary>
		public string Popis { get { return _popis; } }
		///<summary><para>Atribut: Potlačit duplicity [typ_ano_ne] {"A"=Ano; "N"=Ne}</para><para>Db: lcs.filters.force_distinct (char (1) null)</para></summary>
		public string ForceDistinct { get { return _force_distinct; } }
		///<summary><para>Atribut: Dlouhotrvající [typ_ano_ne] {"A"=Ano; "N"=Ne}</para><para>Db: lcs.filters.force_async (char (1) null)</para></summary>
		public string ForceAsync { get { return _force_async; } }
		///<summary><para>Atribut: Zobrazovat [typ_ano_ne_int] {1=Ano; 0=Ne}</para><para>Db: lcs.filters.display (tinyint not null)</para></summary>
		public Int16 Display { get { return _display; } }
		///<summary><para>Atribut: Synchronizační identifikátor</para><para>Db: lcs.filters.sync_id (varchar (255) null)</para></summary>
		public string SyncId { get { return _sync_id; } }
		#endregion
		#region Protected data fields
		#pragma warning disable 1591
		protected int _cislo_filtru;
		protected string _nazev;
		protected int _cislo_tridy;
		protected string _sort_string;
		protected int _zam_id;
		protected string _celou_tridu;
		protected string _rozsah_platnosti;
		protected string _seznam_poradacu;
		protected string _popis;
		protected string _force_distinct;
		protected string _force_async;
		protected Int16 _display;
		protected string _sync_id;
		#pragma warning restore 1591
		#endregion
		#region IDbRecord
		int IDbRecord.RecordNumber { get; set; }
		/// <summary>
		/// Metoda, která umožní rychle naplnit záznam daty z přicházejícího datareaderu.
		/// Typové čtení zajišťuje mapa, metodou map.GetItem...(string columnName).
		/// Metoda má vracet true = data byla skutečně načtena a do záznamu uložena (false = nedošlo k tomu, data se budou načítat genericky).
		/// </summary>
		/// <param name="reader"></param>
		/// <param name="map"></param>
		/// <returns></returns>
		bool IDbFill.FillFromReader(SqlDataReader reader, FieldMapperLoad map)
		{
			_cislo_filtru = (int)map.FillDataIntoField<int>("cislo_filtru", reader);
			_nazev = (string)map.FillDataIntoField<string>("nazev", reader);
			_cislo_tridy = (int)map.FillDataIntoField<int>("cislo_tridy", reader);
			_sort_string = (string)map.FillDataIntoField<string>("sort_string", reader);
			_zam_id = (int)map.FillDataIntoField<int>("zam_id", reader);
			_celou_tridu = (string)map.FillDataIntoField<string>("celou_tridu", reader);
			_rozsah_platnosti = (string)map.FillDataIntoField<string>("rozsah_platnosti", reader);
			_seznam_poradacu = (string)map.FillDataIntoField<string>("seznam_poradacu", reader);
			_popis = (string)map.FillDataIntoField<string>("popis", reader);
			_force_distinct = (string)map.FillDataIntoField<string>("force_distinct", reader);
			_force_async = (string)map.FillDataIntoField<string>("force_async", reader);
			_display = (Int16)map.FillDataIntoField<Int16>("display", reader);
			_sync_id = (string)map.FillDataIntoField<string>("sync_id", reader);
			return true;
		}
		/// <summary>
		/// Metoda, ve které datový objekt připraví podklady pro uložení svých dat do databáze.
		/// Objekt svoje proměnné vloží do exportní mapy prostřednictvím metod map.AddTable(); map.AddColumn();
		/// Pokud objekt chce plnit více tabulek, plní je do mapy postupně, vždy v pořadí {tabulka, sloupce tabulky; další tabulka; sloupce}.
		/// Po naplnění mapy se vrací true.
		/// </summary>
		/// <param name="map"></param>
		/// <returns></returns>
		bool IDbRecord.PrepareSaveData(FieldMapperSave map)
		{ return false; }
		/// <summary>
		/// SQL SELECT pro načtení columnů, odpovídajících této struktuře. Pozor: neobsahuje filtr ani order.
		/// </summary>
		public static string SqlSelect { get { return @"SELECT * FROM lcs.filters"; } }
		#endregion
		#region ROZŠÍŘENÍ O DALŠÍ DATA
		/// <summary>
		/// Informace o třídě, pro kterou je filtr vytvořen
		/// </summary>
		public ClassInfo SourceClassData { get { return Repository.Classes[this.CisloTridy]; } }
		/// <summary>
		/// Seznam všech řádků filtru (filtrační výrazy)
		/// </summary>
		public LinkedList<FilterItemCls> ItemList { get { return this._GetItemList(); } }
		/// <summary>
		/// Seznam všech entit této třídy.
		/// </summary>
		public List<FilterEntityCls> EntityList { get { return this._GetEntityList(); } }
		/// <summary>
		/// Seznam všech entit této třídy, položky jsou typované na interface 
		/// </summary>
		public IEnumerable<INorisClassTreeEntity> EntityIList { get { return this._GetEntityIList(); } }
		/// <summary>
		/// Seznam všech entit této třídy, indexovaný podle čísla entity. 
		/// Entita Main má klíč 1, pod tím klíčem se na ni odvolávají podřízené entity.
		/// </summary>
		public Dictionary<int, FilterEntityCls> EntityDict { get { return this._GetEntityDict(); } }
		#region ON-DEMAND NAČÍTÁNÍ VÁZANÝCH ÚDAJŮ
		/// <summary>
		/// Úložiště seznamu řádků filtru (filtrační výrazy).
		/// </summary>
		private LinkedList<FilterItemCls> _ItemList;
		private object _ItmLocker = new object();
		/// <summary>
		/// Úložiště seznamu entit této třídy (použité třídy ve stromu tříd).
		/// </summary>
		private List<FilterEntityCls> _EntityList;
		private object _EntLocker = new object();
		/// <summary>
		/// Vrátí seznam řádků filtru (filtrační výrazy).
		/// Pokud seznam dosud není načten z databáze, načte se nyní.
		/// Vrací referenci na interní list.
		/// </summary>
		/// <returns></returns>
		private LinkedList<FilterItemCls> _GetItemList()
		{
			LinkedList<FilterItemCls> result = this._ItemList;
			if (result == null)
			{
				lock (this._ItmLocker)
				{
					if (this._ItemList == null)
					{
						string sql = FilterItemCls.SqlSelect + " WHERE cislo_filtru = " + SqlFormat.ToSql(this.CisloFiltru) + " ORDER BY isnull(poradi, 0), pk";
                        List<FilterItemCls> list = Db_Layer.GetList<FilterItemCls>(sql, this.ExternalDataConnector);
						result = new LinkedList<FilterItemCls>();
						foreach (FilterItemCls item in list)
						{
							item.Parent = this;
							result.AddLast(item);   // LinkedList: přidávám nové položky na konec (tj. od začátku)
						}
						this._ItemList = result;
					}
				}
			}
			return result;
		}
		/// <summary>
		/// Vrátí seznam entit této třídy
		/// </summary>
		/// <returns></returns>
		private List<FilterEntityCls> _GetEntityList()
		{
			List<FilterEntityCls> result = this._EntityList;
			if (result == null)
			{
				lock (this._EntLocker)
				{
					if (this._ItemList == null)
					{
						string sql = FilterEntityCls.SqlSelect + " WHERE cislo_filtru = " + SqlFormat.ToSql(this.CisloFiltru) + " ORDER BY isnull(cislo_entity, 0)";
                        result = Db_Layer.GetList<FilterEntityCls>(sql, this.ExternalDataConnector);
						this._EntityList = result;
					}
				}
			}
			return result;
		}
		/// <summary>
		/// Vrátí seznam všech entit této třídy, s položkami přetypovanými na INorisClassTreeEntity
		/// </summary>
		/// <returns></returns>
		private IEnumerable<INorisClassTreeEntity> _GetEntityIList()
		{
			// Tahle funkce je zde proto, že aktuální verze .NET (3.5) 
			//  neummí implicitně převést List<FilterEntityCls> na List<INorisClassTreeEntity>,
			//  ačkoliv třída položek FilterEntityCls sama implementuje INorisClassTreeEntity.
			List<INorisClassTreeEntity> result = new List<INorisClassTreeEntity>();
			List<FilterEntityCls> list = this._GetEntityList();
			foreach (FilterEntityCls entity in list)
				result.Add(entity);
			return result;
		}
		/// <summary>
		/// Vrátí seznam všech entit této třídy, indexovaný podle čísla entity. 
		/// </summary>
		/// <returns></returns>
		private Dictionary<int, FilterEntityCls> _GetEntityDict()
		{
			List<FilterEntityCls> entities = this._GetEntityList();
			Dictionary<int, FilterEntityCls> result = new Dictionary<int, FilterEntityCls>();
			foreach (FilterEntityCls entity in entities)
			{
				if (result.ContainsKey(entity.EntityNumber))
					Throw.SysError(MessageInfo.Get("Ve filtru %0 je chyba v deklaraci entit (FilterPainter): entita %1 se vyskytuje vícekrát.", this.ToString(), entity.EntityNumber));
				else
					result.Add(entity.EntityNumber, entity);
			}
			return result;
		}
		#endregion
		#endregion
	}
	#region CLASS FilterItemCls : Třída odvozená z tabulky lcs.nis_filters
	/// <summary>
	/// FilterItemCls : Tato tabulka (lcs.nis_filters) není navázaná k žádné Noris třídě.
	/// Data načtena z tabulky lcs.nis_filters
	/// </summary>
	public partial class FilterItemCls : Noris.Schedule.Support.Sql.IDbRecord, INorisClassTreeEntry
	{
		#region Konstruktor
		/// <summary>
		/// Implicitní konstruktor
		/// </summary>
		public FilterItemCls()
		{ }
		/// <summary>
		/// Vizualizace
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			return "Item: " + this.ColumnVis + " (" + this.ColumnReal + "); Entity = " + this.EntityNumber.ToString();
		}
		/// <summary>
		/// Číslo pořadí: Název sloupce viditelný
		/// </summary>
		public virtual string ReferNazev
		{ get { return this.Poradi.ToString() + ": " + this.ColumnVis; } }
		#endregion
		#region Public systém property
		/// <summary>IDbRecord.RecordNumber : musí konkrétně implementovat set, protože DbLayer po uložení nového záznamu (kde RecordNumber == 0) do něj vloží přidělený klíč</summary>
		int IDbRecord.RecordNumber { get { return this._pk; } set { this._pk = value; } }
		#endregion
		#region Public data property
		///<summary><para>Db: lcs.nis_filters.cislo_filtru (int not null)</para></summary>
		public int CisloFiltru { get { return _cislo_filtru; } }
		///<summary><para>Db: lcs.nis_filters.left_braces (varchar (3) null)</para></summary>
		public string LeftBraces { get { return _left_braces; } }
		///<summary><para>Db: lcs.nis_filters.column_vis (varchar (120) not null)</para></summary>
		public string ColumnVis { get { return _column_vis; } }
		///<summary><para>Db: lcs.nis_filters.column_real (varchar (255) not null)</para></summary>
		public string ColumnReal { get { return _column_real; } }
		///<summary><para>Db: lcs.nis_filters.relace (varchar (20) null)</para></summary>
		public string Relace { get { return _relace; } }
		///<summary><para>Db: lcs.nis_filters.hodnota_vis (varchar (255) null)</para></summary>
		public string HodnotaVis { get { return _hodnota_vis; } }
		///<summary><para>Db: lcs.nis_filters.hodnota_vis2 (varchar (255) null)</para></summary>
		public string HodnotaVis2 { get { return _hodnota_vis2; } }
		///<summary><para>Db: lcs.nis_filters.hodnota_pointer (int null)</para></summary>
		public SqlInt32 HodnotaPointer { get { return _hodnota_pointer; } }
		///<summary><para>Db: lcs.nis_filters.datatyp (varchar (40) not null)</para></summary>
		public string Datatyp { get { return _datatyp; } }
		///<summary><para>Db: lcs.nis_filters.right_braces (varchar (3) null)</para></summary>
		public string RightBraces { get { return _right_braces; } }
		///<summary><para>Db: lcs.nis_filters.spojitko (varchar (3) null)</para></summary>
		public string Spojitko { get { return _spojitko; } }
		///<summary><para>Db: lcs.nis_filters.cislo_vztahu (int null)</para></summary>
		public SqlInt32 CisloVztahu { get { return _cislo_vztahu; } }
		///<summary><para>Db: lcs.nis_filters.cislo_poradace (int null)</para></summary>
		public SqlInt32 CisloPoradace { get { return _cislo_poradace; } }
		///<summary><para>Db: lcs.nis_filters.cislo_tridy (int null)</para></summary>
		public SqlInt32 CisloTridy { get { return _cislo_tridy; } }
		///<summary><para>Db: lcs.nis_filters.cislo_hladiska (smallint null)</para></summary>
		public SqlInt16 CisloHladiska { get { return _cislo_hladiska; } }
		///<summary><para>Db: lcs.nis_filters.typ_radky (varchar (10) null)</para></summary>
		public string TypRadky { get { return _typ_radky; } }
		///<summary><para>Db: lcs.nis_filters.typ_vztahu (varchar (10) null)</para></summary>
		public string TypVztahu { get { return _typ_vztahu; } }
		///<summary><para>Db: lcs.nis_filters.zobrcol (char (1) null)</para></summary>
		public string Zobrcol { get { return _zobrcol; } }
		///<summary><para>Db: lcs.nis_filters.expression (varchar (1500) null)</para></summary>
		public string Expression { get { return _expression; } }
		///<summary><para>Db: lcs.nis_filters.entita (smallint null)</para></summary>
		public SqlInt16 Entita { get { return _entita; } }
		///<summary><para>Db: lcs.nis_filters.poradi (smallint null)</para></summary>
		public SqlInt16 Poradi { get { return _poradi; } }
		///<summary><para>Db: lcs.nis_filters.pk (int not null)</para></summary>
		public int Pk { get { return _pk; } }
		#endregion
		#region Protected data fields
		#pragma warning disable 1591
		protected int _cislo_filtru;
		protected string _left_braces;
		protected string _column_vis;
		protected string _column_real;
		protected string _relace;
		protected string _hodnota_vis;
		protected string _hodnota_vis2;
		protected SqlInt32 _hodnota_pointer;
		protected string _datatyp;
		protected string _right_braces;
		protected string _spojitko;
		protected SqlInt32 _cislo_vztahu;
		protected SqlInt32 _cislo_poradace;
		protected SqlInt32 _cislo_tridy;
		protected SqlInt16 _cislo_hladiska;
		protected string _typ_radky;
		protected string _typ_vztahu;
		protected string _zobrcol;
		protected string _expression;
		protected SqlInt16 _entita;
		protected SqlInt16 _poradi;
		protected int _pk;
		#pragma warning restore 1591
		#endregion
        #region IDbRecord
        /// <summary>
		/// Metoda, která umožní rychle naplnit záznam daty z přicházejícího datareaderu.
		/// Typové čtení zajišťuje mapa, metodou map.GetItem...(string columnName).
		/// Metoda má vracet true = data byla skutečně načtena a do záznamu uložena (false = nedošlo k tomu, data se budou načítat genericky).
		/// </summary>
		/// <param name="reader"></param>
		/// <param name="map"></param>
		/// <returns></returns>
		bool IDbFill.FillFromReader(SqlDataReader reader, FieldMapperLoad map)
		{
			_cislo_filtru = (int)map.FillDataIntoField<int>("cislo_filtru", reader);
			_left_braces = (string)map.FillDataIntoField<string>("left_braces", reader);
			_column_vis = (string)map.FillDataIntoField<string>("column_vis", reader);
			_column_real = (string)map.FillDataIntoField<string>("column_real", reader);
			_relace = (string)map.FillDataIntoField<string>("relace", reader);
			_hodnota_vis = (string)map.FillDataIntoField<string>("hodnota_vis", reader);
			_hodnota_vis2 = (string)map.FillDataIntoField<string>("hodnota_vis2", reader);
			_hodnota_pointer = (SqlInt32)map.FillDataIntoField<SqlInt32>("hodnota_pointer", reader);
			_datatyp = (string)map.FillDataIntoField<string>("datatyp", reader);
			_right_braces = (string)map.FillDataIntoField<string>("right_braces", reader);
			_spojitko = (string)map.FillDataIntoField<string>("spojitko", reader);
			_cislo_vztahu = (SqlInt32)map.FillDataIntoField<SqlInt32>("cislo_vztahu", reader);
			_cislo_poradace = (SqlInt32)map.FillDataIntoField<SqlInt32>("cislo_poradace", reader);
			_cislo_tridy = (SqlInt32)map.FillDataIntoField<SqlInt32>("cislo_tridy", reader);
			_cislo_hladiska = (SqlInt16)map.FillDataIntoField<SqlInt16>("cislo_hladiska", reader);
			_typ_radky = (string)map.FillDataIntoField<string>("typ_radky", reader);
			_typ_vztahu = (string)map.FillDataIntoField<string>("typ_vztahu", reader);
			_zobrcol = (string)map.FillDataIntoField<string>("zobrcol", reader);
			_expression = (string)map.FillDataIntoField<string>("expression", reader);
			_entita = (SqlInt16)map.FillDataIntoField<SqlInt16>("entita", reader);
			_poradi = (SqlInt16)map.FillDataIntoField<SqlInt16>("poradi", reader);
			_pk = (int)map.FillDataIntoField<int>("pk", reader);
			return true;
		}
		/// <summary>
		/// Zajistí přípravu svých dat do podkladové vrstvy pro uložení do databáze.
		/// Subjektové třídy musí nejprve volat SubjectCls.PrepareSaveData(this, map);, 
		/// tím se uloží data do tabulky subjektů (a pro nové záznamy se vygeneruje číslo subjektu).
		/// Nonsubjektové třídy to volat nesmí.
		/// </summary>
		/// <param name="map"></param>
		/// <returns></returns>
		bool IDbRecord.PrepareSaveData(FieldMapperSave map)
        { return false; }
        /// <summary>
		/// SQL SELECT pro načtení columnů, odpovídajících této struktuře. Pozor: neobsahuje filtr ani order.
		/// </summary>
		public static string SqlSelect { get { return @"SELECT * FROM lcs.nis_filters"; } }
		#endregion
		#region IMPLEMENTACE INorisClassTreeEntry
		/// <summary>
		/// Číslo entity, do které se tento prvek hlásí (její data čte)
		/// </summary>
		int INorisClassTreeEntry.EntityNumber { get { return (this.Entita.IsNull ? 1 : this.Entita.Value); } }
		/// <summary>
		/// Plný název db sloupce, který tato položka čte.
        /// Zde může být i výraz (typicky: "(select case when .. then .. else .. end as data from lcs.sk_polozka pol left outer join lcs.sk_hlavicka hl on hl.cislo_subjektu = pol.cislo_subjektu where pol.cislo_subjektu = lcs.sk_polozka.cislo_subjektu and pol.cislo_objektu = lcs.sk_polozka.cislo_objektu)".)
        /// </summary>
		string INorisClassTreeEntry.DataColumnSource { get { return (!String.IsNullOrEmpty(this.Expression) ? this.Expression : this.ColumnReal); } }
		/// <summary>
		/// Číslo třídy dat, ze které tato položka čte data
		/// </summary>
		int INorisClassTreeEntry.ClassNumber { get { return (this.CisloTridy.IsNull ? 0 : this.CisloTridy.Value); } }
		/// <summary>
		/// Číslo pořadače dat, ze kterého tato položka čte data
		/// </summary>
		int INorisClassTreeEntry.FolderNumber { get { return (this.CisloPoradace.IsNull ? 0 : this.CisloPoradace.Value); } }
		#endregion
		#region ROZŠÍŘENÁ DATA
		/// <summary>
		/// Číslo této entity. Int32, namísto SqlInt32. Žádný prvek není null, preventivně převedu DbNull na 1.
		/// </summary>
		public int EntityNumber { get { return (this.Entita.IsNull ? 1 : this.Entita.Value); } }
        /// <summary>
        /// Vrací příznak true, pokud tato část filtru obsahuje výraz
        /// </summary>
        public bool IsExpression { get { return !String.IsNullOrEmpty(this.Expression); } }
        /// <summary>
        /// Data třídy.
        /// Pokud je tato položka filtru vztažená k pořadači (tedy this.CisloTridy je null), 
        /// pak zde se vrátí data o třídě daného pořadače.
        /// Pokud tato položka filtru není vztažená ani k třídě, ani k pořadači, vrací se null.
        /// </summary>
        public ClassInfo ClassData
        {
            get
            {
                if (!this.CisloTridy.IsNull) return Repository.Classes[this.CisloTridy.Value];
                if (!this.CisloPoradace.IsNull) return Repository.Folders[this.CisloPoradace.Value].ClassData;
                return null;
            }
        }
		#endregion
	}
	#endregion
	#region CLASS FilterEntityCls : Třída odvozená z tabulky lcs.filter_painter
	/// <summary>
	/// FilterEntityCls : Tato tabulka (lcs.filter_painter) není navázaná k žádné Noris třídě.
	/// Data načtena z tabulky lcs.filter_painter
	/// </summary>
	public partial class FilterEntityCls : Noris.Schedule.Support.Sql.IDbRecord, INorisClassTreeEntity
	{
		#region Konstruktor
		/// <summary>
		/// Implicitní konstruktor
		/// </summary>
		public FilterEntityCls()
		{ }
		/// <summary>
		/// Vizualizace
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			return "Entity " + this.EntityNumber.ToString() + ": " + this.NazevEntity + "; Parent = " + (this.ParentEntita.IsNull ? "none" : this.ParentEntita.Value.ToString());
		}
		#endregion
		#region Public systém property
		/// <summary>IDbRecord.RecordNumber : musí konkrétně implementovat set, protože DbLayer po uložení nového záznamu (kde RecordNumber == 0) do něj vloží přidělený klíč</summary>
		int IDbRecord.RecordNumber { get { return this._pk; } set { this._pk = value; } }
		#endregion
		#region Public data property
		///<summary><para>Db: lcs.filter_painter.cislo_filtru (int not null)</para></summary>
		public int CisloFiltru { get { return _cislo_filtru; } }
		///<summary><para>Db: lcs.filter_painter.cislo_tridy (int not null)</para></summary>
		public int CisloTridy { get { return _cislo_tridy; } }
		///<summary><para>Db: lcs.filter_painter.cislo_poradace (int null)</para></summary>
		public SqlInt32 CisloPoradace { get { return _cislo_poradace; } }
		///<summary><para>Db: lcs.filter_painter.cislo_vztahu (int not null)</para></summary>
		public int CisloVztahu { get { return _cislo_vztahu; } }
		///<summary><para>Db: lcs.filter_painter.nazev_entity (varchar (40) not null)</para></summary>
		public string NazevEntity { get { return _nazev_entity; } }
		///<summary><para>Db: lcs.filter_painter.strana (char (1) null)</para></summary>
		public string Strana { get { return _strana; } }
		///<summary><para>Db: lcs.filter_painter.pocet_subentit (smallint null)</para></summary>
		public SqlInt16 PocetSubentit { get { return _pocet_subentit; } }
		///<summary><para>Db: lcs.filter_painter.parent_entita (smallint null)</para></summary>
		public SqlInt16 ParentEntita { get { return _parent_entita; } }
		///<summary><para>Db: lcs.filter_painter.x (smallint null)</para></summary>
		public SqlInt16 X { get { return _x; } }
		///<summary><para>Db: lcs.filter_painter.y (smallint null)</para></summary>
		public SqlInt16 Y { get { return _y; } }
		///<summary><para>Db: lcs.filter_painter.cislo_entity (smallint null)</para></summary>
		public SqlInt16 CisloEntity { get { return _cislo_entity; } }
		///<summary><para>Db: lcs.filter_painter.type (int not null)</para></summary>
		public int Type { get { return _type; } }
		///<summary><para>Db: lcs.filter_painter.pk (int not null)</para></summary>
		public int Pk { get { return _pk; } }
		///<summary><para>Db: lcs.filter_painter.join_type (char (1) null)</para></summary>
		public string JoinType { get { return _join_type; } }
		#endregion
		#region Protected data fields
		#pragma warning disable 1591
		protected int _cislo_filtru;
		protected int _cislo_tridy;
		protected SqlInt32 _cislo_poradace;
		protected int _cislo_vztahu;
		protected string _nazev_entity;
		protected string _strana;
		protected SqlInt16 _pocet_subentit;
		protected SqlInt16 _parent_entita;
		protected SqlInt16 _x;
		protected SqlInt16 _y;
		protected SqlInt16 _cislo_entity;
		protected int _type;
		protected int _pk;
		protected string _join_type;
		#pragma warning restore 1591
		#endregion
		#region FILL FROM READER, SAVE RECORD (VOID), STATIC GENERÁTORY SELECTU
		/// <summary>
		/// Metoda, která umožní rychle naplnit záznam daty z přicházejícího datareaderu.
		/// Typové čtení zajišťuje mapa, metodou map.GetItem...(string columnName).
		/// Metoda má vracet true = data byla skutečně načtena a do záznamu uložena (false = nedošlo k tomu, data se budou načítat genericky).
		/// </summary>
		/// <param name="reader"></param>
		/// <param name="map"></param>
		/// <returns></returns>
		bool IDbFill.FillFromReader(SqlDataReader reader, FieldMapperLoad map)
		{
			_cislo_filtru = (int)map.FillDataIntoField<int>("cislo_filtru", reader);
			_cislo_tridy = (int)map.FillDataIntoField<int>("cislo_tridy", reader);
			_cislo_poradace = (SqlInt32)map.FillDataIntoField<SqlInt32>("cislo_poradace", reader);
			_cislo_vztahu = (int)map.FillDataIntoField<int>("cislo_vztahu", reader);
			_nazev_entity = (string)map.FillDataIntoField<string>("nazev_entity", reader);
			_strana = (string)map.FillDataIntoField<string>("strana", reader);
			_pocet_subentit = (SqlInt16)map.FillDataIntoField<SqlInt16>("pocet_subentit", reader);
			_parent_entita = (SqlInt16)map.FillDataIntoField<SqlInt16>("parent_entita", reader);
			_x = (SqlInt16)map.FillDataIntoField<SqlInt16>("x", reader);
			_y = (SqlInt16)map.FillDataIntoField<SqlInt16>("y", reader);
			_cislo_entity = (SqlInt16)map.FillDataIntoField<SqlInt16>("cislo_entity", reader);
			_type = (int)map.FillDataIntoField<int>("type", reader);
			_pk = (int)map.FillDataIntoField<int>("pk", reader);
			_join_type = (string)map.FillDataIntoField<string>("join_type", reader);
			return true;
		}
		/// <summary>
		/// Zajistí přípravu svých dat do podkladové vrstvy pro uložení do databáze.
		/// Subjektové třídy musí nejprve volat SubjectCls.PrepareSaveData(this, map);, 
		/// tím se uloží data do tabulky subjektů (a pro nové záznamy se vygeneruje číslo subjektu).
		/// Nonsubjektové třídy to volat nesmí.
		/// </summary>
		/// <param name="map"></param>
		/// <returns></returns>
		bool IDbRecord.PrepareSaveData(FieldMapperSave map)
		{
			return false;
		}
		/// <summary>
		/// SQL SELECT pro načtení columnů, odpovídajících této struktuře. Pozor: neobsahuje filtr ani order.
		/// </summary>
		public static string SqlSelect { get { return @"SELECT * FROM lcs.filter_painter"; } }
		#endregion
		#region IMPLEMENTACE INorisClassTreeEntity
		/// <summary>
		/// Číslo této entity
		/// </summary>
		int INorisClassTreeEntity.EntityNumber { get { return (this.CisloEntity.IsNull ? 1 : this.CisloEntity.Value); } }
		/// <summary>
		/// Číslo parent entity
		/// </summary>
		int INorisClassTreeEntity.ParentEntityNumber { get { return (this.ParentEntita.IsNull ? 0 : this.ParentEntita.Value); ; } }
		/// <summary>
		/// Číslo třídy dat v této entitě (nebo 0)
		/// </summary>
		int INorisClassTreeEntity.ClassNumber { get { return this.CisloTridy; } }
		/// <summary>
		/// Číslo pořadače dat v této entitě (nebo 0)
		/// </summary>
		int INorisClassTreeEntity.FolderNumber { get { return (this.CisloPoradace.IsNull ? 0 : this.CisloPoradace.Value); } }
		/// <summary>
		/// Číslo vztahu, kterým je tato entita navázaná na svého parenta
		/// </summary>
		int INorisClassTreeEntity.RelationNumber { get { return this.CisloVztahu; } }
		/// <summary>
		/// Strana vztahu
		/// </summary>
		RelationSideType INorisClassTreeEntity.RelationSide { get { return RelationInfo.ConvertStringToRelationSide(this._strana); } }
		#endregion
		#region ROZŠÍŘENÁ DATA
		/// <summary>
		/// Číslo této entity. Hlavní entita má číslo 1 (v property this.CisloEntity má DbNull).
		/// </summary>
		public int EntityNumber { get { return (this.CisloEntity.IsNull ? 1 : this.CisloEntity.Value); } }
        /// <summary>
        /// Číslo parenta této entity. Pokud tato entita nemá parenta, je zde 0 (entita 0 se nevyskytuje nikdy).
        /// </summary>
        public int ParentEntityNumber { get { return (this.ParentEntita.IsNull ? 0 : this.ParentEntita.Value); } }
        /// <summary>
        /// Příznak, že tato entita má parenta (její ParentEntityNumber je větš ínež 0).
        /// </summary>
        public bool HasParentEntity { get { return (!this.ParentEntita.IsNull && this.ParentEntita.Value > 0); } }
        /// <summary>
        /// Data třídy.
        /// </summary>
        public ClassInfo ClassData { get { return Repository.Classes[this.CisloTridy]; } }
		#endregion
	}
	#endregion
	#endregion
	#region CLASS TemplatesCls + TemplateInfo ( + ...)
	/// <summary>
	/// Sada šablon
	/// </summary>
	public class TemplatesCls : RepositorySegmentCls<Int32, TemplateInfo>
	{
		/// <summary>
		/// Konstruktor. Na vstupu očekává maximální počet záznamů, které může držet v paměti.
		/// Pokud by načítal další záznamy, pak nejstarší z paměti uvolní.
		/// </summary>
		/// <param name="maxItemCnt">Nejvyšší počet záznamů. -1 = neomezeně. 0 = žádný !!!</param>
		public TemplatesCls(int maxItemCnt)
			: base(maxItemCnt)
		{ }
		/// <summary>
		/// Tato property vrátí SQL SELECT pro načtení jednoho záznamu s daty.
		/// SQL SELECT musí ve vhodném místě obsahovat token {{RecordNumber}}, na jehož místo jádro dosadí číslo hledaného záznamu nebo seznam čísel.
		/// Konkrétně, select by měl obsahovat frázi: "WHERE cislo_tridy {{RecordNumber}}", 
		/// jádro pak dosadí buď "WHERE cislo_tridy = 12345", 
		/// anebo dosadí "WHERE cislo_tridy in (1,2,3,4,5,6,7)", podle požadavku.
		/// Kdo nemá rád explicitní texty, určitě rád použije konstantu TOKEN_RECORD_NUMBER.
		/// </summary>
		protected override string SqlSelect
		{
			get
			{
				return TemplateInfo.SqlSelect + " WHERE cislo_tridy " + TOKEN_RECORD_NUMBER;
			}
		}
		/// <summary>
		/// Háček volaný po načtení záznamu z databáze.
		/// Háček se volá i když je přepsaná virtuální metoda this.GetDataItem(), je volán před háčkem DataItemAddBefore() / DataItemValidateBefore()
		/// </summary>
		/// <param name="item"></param>
		protected override void DataItemRetrieveAfter(TemplateInfo item)
		{
			base.DataItemRetrieveAfter(item);
		}
	}
	/// <summary>
	/// Informace o šabloně
	/// </summary>
	public class TemplateInfo : RepositorySegmentItem<Int32>, IDbRecord
	{
		#region Abstract and overrides
		/// <summary>
		/// Klíčová hodnota záznamu. Potomek musí implementovat = namapovat na konkrétní property, která nese skutečný klíč záznamu.
		/// </summary>
		protected override Int32 CurrentKeyValue { get { return this._cislo_tridy; } set { this._cislo_tridy = value; } }
		/// <summary>
		/// Číslo záznamu. Potomek musí implementovat = namapovat na konkrétní property, která nese skutečné číslo záznamu.
		/// </summary>
		// public override Int32 CurrentRecordNumber { get { return this._cislo_tridy; } protected set { this._cislo_tridy = value; } }
		/// <summary>
		/// Vizualizace
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			return "Template " + this.CisloSablony.ToString() + ": " + this.Nazev;
		}
		#endregion
		#region Public data property

		// lcs.template:
		///<summary><para>Atribut: Číslo</para><para>Db: lcs.template.cislo_template (int not null)</para></summary>
		public int CisloTemplate { get { return _cislo_template; } }
		///<summary><para>Atribut: Název</para><para>Db: lcs.template.nazev (varchar (40) not null)</para></summary>
		public string Nazev { get { return _nazev; } }
		///<summary><para>Vztah 6252: Třída (zprava: Šablony)</para><para>Db: lcs.template.cislo_tridy (int not null)</para></summary>
		public int CisloTridy { get { return _cislo_tridy; } }
		///<summary><para>Atribut: Datawindow</para><para>Db: lcs.template.nazev_dw (varchar (80) not null)</para></summary>
		public string NazevDw { get { return _nazev_dw; } }
		///<summary><para>Atribut: Knihovna</para><para>Db: lcs.template.nazev_pbl (varchar (12) not null)</para></summary>
		public string NazevPbl { get { return _nazev_pbl; } }
		///<summary><para>Atribut: Interní/externí [template_priznak_ie] {"I"=I; "E"=E}</para><para>Db: lcs.template.priznak_ie (char (1) null)</para></summary>
		public string PriznakIe { get { return _priznak_ie; } }
		///<summary><para>Atribut: Externí aplikace</para><para>Db: lcs.template.ext_appl (varchar (255) null)</para></summary>
		public string ExtAppl { get { return _ext_appl; } }
		///<summary><para>Atribut: Typ [template_typ] {"F"=Formulářová šablona; "T"=Přehledová šablona; "U"=Formulářová šablona bez filtrování; "S"=Přehledová šablona bez filtrování}</para><para>Db: lcs.template.typ (char (1) null)</para></summary>
		public string Typ { get { return _typ; } }
		///<summary><para>Db: lcs.template.zam_id (int null)</para></summary>
		public SqlInt32 ZamId { get { return _zam_id; } }
		///<summary><para>Db: lcs.template.rozsah_platnosti (char (1) null)</para></summary>
		public string RozsahPlatnosti { get { return _rozsah_platnosti; } }
		///<summary><para>Db: lcs.template.seznam_poradacu (varchar (1000) null)</para></summary>
		public string SeznamPoradacu { get { return _seznam_poradacu; } }
		///<summary><para>Atribut: Popis [multilline_poznamka]</para><para>Db: lcs.template.popis (varchar (255) null)</para></summary>
		public string Popis { get { return _popis; } }
		///<summary><para>Atribut: Vztah</para><para>Db: lcs.template.vztah (int null)</para></summary>
		public SqlInt32 Vztah { get { return _vztah; } }
		///<summary><para>Atribut: Dlouhotrvající [typ_ano_ne] {"A"=Ano; "N"=Ne}</para><para>Db: lcs.template.force_async (char (1) not null)</para></summary>
		public string ForceAsync { get { return _force_async; } }
		///<summary><para>Atribut: Počet kopií</para><para>Db: lcs.template.pocet_kopii (smallint null)</para></summary>
		public SqlInt16 PocetKopii { get { return _pocet_kopii; } }
		///<summary><para>Atribut: Auditovat [typ_ano_ne] {"A"=Ano; "N"=Ne}</para><para>Db: lcs.template.auditovat (char (1) not null)</para></summary>
		public string Auditovat { get { return _auditovat; } }
		///<summary><para>Atribut: Pouze .NET</para><para>Db: lcs.template.pouze_net (varchar (1) not null)</para></summary>
		public string PouzeNet { get { return _pouze_net; } }
		///<summary><para>Db: lcs.template.count_of_use_is_active (char (1) null)</para></summary>
		public string CountOfUseIsActive { get { return _count_of_use_is_active; } }
		///<summary><para>Db: lcs.template.startcounting (datetime null)</para></summary>
		public SqlDateTime Startcounting { get { return _startcounting; } }
		///<summary><para>Db: lcs.template.stopcounting (datetime null)</para></summary>
		public SqlDateTime Stopcounting { get { return _stopcounting; } }
		///<summary><para>Atribut: Datum změny</para><para>Db: lcs.template.datum_zmeny (smalldatetime null)</para></summary>
		public SqlDateTime DatumZmeny { get { return _datum_zmeny; } }
		///<summary><para>Atribut: Čas importu</para><para>Db: lcs.template.importtime (datetime null)</para></summary>
		public SqlDateTime Importtime { get { return _importtime; } }
		///<summary><para>Atribut: Evidované tisky [typ_ano_ne] {"A"=Ano; "N"=Ne}</para><para>Db: lcs.template.evidovane_tisky (char (1) null)</para></summary>
		public string EvidovaneTisky { get { return _evidovane_tisky; } }
		///<summary><para>Atribut: Původ šablony [typ_template_origin] {"U"=Uživatelská; "N"=Systémová; "S"=Správcovská}</para><para>Db: lcs.template.origin (char (1) not null)</para></summary>
		public string Origin { get { return _origin; } }
		///<summary><para>Atribut: Druh šablony [template_kind] {"L"=Legislativní; "C"=Kontrolní; "O"=Ostatní}</para><para>Db: lcs.template.kind (char (1) null)</para></summary>
		public string Kind { get { return _kind; } }
		///<summary><para>Atribut: Help</para><para>Db: lcs.template.help (ntext null)</para></summary>
		public string Help { get { return _help; } }
		///<summary><para>Atribut: Bez kontroly počtu záznamů [typ_ano_ne] {"A"=Ano; "N"=Ne}</para><para>Db: lcs.template.bez_kontroly_poctu_zaznamu (char (1) not null)</para></summary>
		public string BezKontrolyPoctuZaznamu { get { return _bez_kontroly_poctu_zaznamu; } }
		///<summary><para>Atribut: Použití šablony na databázi [Template_Using_Type] {"M"=Pouze ostrá databáze; "A"=Pouze archivní databáze; "B"=Ostrá i archivní databáze}</para><para>Db: lcs.template.pouziti_sablony_na_databazi (char (1) not null)</para></summary>
		public string PouzitiSablonyNaDatabazi { get { return _pouziti_sablony_na_databazi; } }
		///<summary><para>Atribut: Zobrazovat [typ_ano_ne] {"A"=Ano; "N"=Ne}</para><para>Db: lcs.template.show (char (1) null)</para></summary>
		public string Show { get { return _show; } }
		///<summary><para>Atribut: Platnost do</para><para>Db: lcs.template.legislative_validity_until (smalldatetime null)</para></summary>
		public SqlDateTime LegislativeValidityUntil { get { return _legislative_validity_until; } }
		///<summary><para>Atribut: Způsob instalace [rozhrani_tridy_trideni] {0=Automaticky se třídou; 1=Dle konfigurace modulu; 2=Vyřazeno}</para><para>Db: lcs.template.rozhrani_tridy (int null)</para></summary>
		public SqlInt32 RozhraniTridy { get { return _rozhrani_tridy; } }
		///<summary><para>Atribut: Namespace</para><para>Db: lcs.template.namespace (varchar (40) null)</para></summary>
		public string Namespace { get { return _namespace; } }
		///<summary><para>Atribut: Způsob generování názvu souboru [tvorba_nazvu_souboru] {"a"=název šablony + reference + název; "b"=reference + název šablony; "c"=název + název šablony; "d"=reference + název + název šablony; "e"=reference + název; "f"=reference záznamu; "g"=název záznamu}</para><para>Db: lcs.template.tvorba_nazvu_souboru (char (1) null)</para></summary>
		public string TvorbaNazvuSouboru { get { return _tvorba_nazvu_souboru; } }
		///<summary><para>Atribut: Synchronizační identifikátor</para><para>Db: lcs.template.sync_id (varchar (255) null)</para></summary>
		public string SyncId { get { return _sync_id; } }
		///<summary><para>Atribut: Lze aplikovat do přehledu [typ_ano_ne] {"A"=Ano; "N"=Ne}</para><para>Db: lcs.template.lze_aplikovat_do_prehledu (char (1) null)</para></summary>
		public string LzeAplikovatDoPrehledu { get { return _lze_aplikovat_do_prehledu; } }

		// lcs.noris_gs_template:
		///<summary><para>Db: lcs.noris_gs_template.pk (int not null)</para></summary>
		public int Pk { get { return _pk; } }
		///<summary><para>Db: lcs.noris_gs_template.cislo_sablony (int null)</para></summary>
		public SqlInt32 CisloSablony { get { return _cislo_sablony; } }
		///<summary><para>Db: lcs.noris_gs_template.filter_act (int null)</para></summary>
		public SqlInt32 FilterAct { get { return _filter_act; } }
		///<summary><para>Db: lcs.noris_gs_template.filter_defa (int null)</para></summary>
		public SqlInt32 FilterDefa { get { return _filter_defa; } }
		///<summary><para>Db: lcs.noris_gs_template.b_save (smallint null)</para></summary>
		public SqlInt16 BSave { get { return _b_save; } }
		///<summary><para>Db: lcs.noris_gs_template.b_distinct (smallint null)</para></summary>
		public SqlInt16 BDistinct { get { return _b_distinct; } }
		///<summary><para>Db: lcs.noris_gs_template.b_enablesort (smallint null)</para></summary>
		public SqlInt16 BEnablesort { get { return _b_enablesort; } }
		///<summary><para>Db: lcs.noris_gs_template.b_gridlines (smallint null)</para></summary>
		public SqlInt16 BGridlines { get { return _b_gridlines; } }
		///<summary><para>Db: lcs.noris_gs_template.b_gridlinesprint (smallint null)</para></summary>
		public SqlInt16 BGridlinesprint { get { return _b_gridlinesprint; } }
		///<summary><para>Db: lcs.noris_gs_template.b_ask_print (smallint null)</para></summary>
		public SqlInt16 BAskPrint { get { return _b_ask_print; } }
		///<summary><para>Db: lcs.noris_gs_template.b_landscape (smallint null)</para></summary>
		public SqlInt16 BLandscape { get { return _b_landscape; } }
		///<summary><para>Db: lcs.noris_gs_template.b_usegroupdef (smallint null)</para></summary>
		public SqlInt16 BUsegroupdef { get { return _b_usegroupdef; } }
		///<summary><para>Db: lcs.noris_gs_template.s_reportname (varchar (255) null)</para></summary>
		public string SReportname { get { return _s_reportname; } }
		///<summary><para>Db: lcs.noris_gs_template.s_mark (varchar (1000) null)</para></summary>
		public string SMark { get { return _s_mark; } }
		///<summary><para>Db: lcs.noris_gs_template.b_onlygroups (smallint null)</para></summary>
		public SqlInt16 BOnlygroups { get { return _b_onlygroups; } }
		///<summary><para>Db: lcs.noris_gs_template.b_onlygroup (smallint null)</para></summary>
		public SqlInt16 BOnlygroup { get { return _b_onlygroup; } }
		///<summary><para>Db: lcs.noris_gs_template.printfont (char (30) null)</para></summary>
		public string Printfont { get { return _printfont; } }
		///<summary><para>Db: lcs.noris_gs_template.temlate_size (char (20) null)</para></summary>
		public string TemlateSize { get { return _temlate_size; } }
		///<summary><para>Db: lcs.noris_gs_template.b_printwhere (smallint not null)</para></summary>
		public Int16 BPrintwhere { get { return _b_printwhere; } }
		///<summary><para>Db: lcs.noris_gs_template.b_wrap_title (char (1) null)</para></summary>
		public string BWrapTitle { get { return _b_wrap_title; } }
		///<summary><para>Db: lcs.noris_gs_template.b_groupquery (smallint not null)</para></summary>
		public Int16 BGroupquery { get { return _b_groupquery; } }
		///<summary><para>Db: lcs.noris_gs_template.b_disablesortchange (smallint not null)</para></summary>
		public Int16 BDisablesortchange { get { return _b_disablesortchange; } }
		///<summary><para>Db: lcs.noris_gs_template.charts (ntext null)</para></summary>
		public string Charts { get { return _charts; } }
		///<summary><para>Db: lcs.noris_gs_template.default_view (int null)</para></summary>
		public SqlInt32 DefaultView { get { return _default_view; } }

		#endregion
		#region Protected data fields
		#pragma warning disable 1591
		// lcs.template:
		protected int _cislo_template;
		protected string _nazev;
		protected int _cislo_tridy;
		protected string _nazev_dw;
		protected string _nazev_pbl;
		protected string _priznak_ie;
		protected string _ext_appl;
		protected string _typ;
		protected SqlInt32 _zam_id;
		protected string _rozsah_platnosti;
		protected string _seznam_poradacu;
		protected string _popis;
		protected SqlInt32 _vztah;
		protected string _force_async;
		protected SqlInt16 _pocet_kopii;
		protected string _auditovat;
		protected string _pouze_net;
		protected string _count_of_use_is_active;
		protected SqlDateTime _startcounting;
		protected SqlDateTime _stopcounting;
		protected SqlDateTime _datum_zmeny;
		protected SqlDateTime _importtime;
		protected string _evidovane_tisky;
		protected string _origin;
		protected string _kind;
		protected string _help;
		protected string _bez_kontroly_poctu_zaznamu;
		protected string _pouziti_sablony_na_databazi;
		protected string _show;
		protected SqlDateTime _legislative_validity_until;
		protected SqlInt32 _rozhrani_tridy;
		protected string _namespace;
		protected string _tvorba_nazvu_souboru;
		protected string _sync_id;
		protected string _lze_aplikovat_do_prehledu;

		// lcs.noris_gs_template:
		protected int _pk;
		protected SqlInt32 _cislo_sablony;
		protected SqlInt32 _filter_act;
		protected SqlInt32 _filter_defa;
		protected SqlInt16 _b_save;
		protected SqlInt16 _b_distinct;
		protected SqlInt16 _b_enablesort;
		protected SqlInt16 _b_gridlines;
		protected SqlInt16 _b_gridlinesprint;
		protected SqlInt16 _b_ask_print;
		protected SqlInt16 _b_landscape;
		protected SqlInt16 _b_usegroupdef;
		protected string _s_reportname;
		protected string _s_mark;
		protected SqlInt16 _b_onlygroups;
		protected SqlInt16 _b_onlygroup;
		protected string _printfont;
		protected string _temlate_size;
		protected Int16 _b_printwhere;
		protected string _b_wrap_title;
		protected Int16 _b_groupquery;
		protected Int16 _b_disablesortchange;
		protected string _charts;
		protected SqlInt32 _default_view;

		#pragma warning restore 1591
		#endregion
		#region IDbRecord
		int IDbRecord.RecordNumber { get; set; }
		/// <summary>
		/// Metoda, která umožní rychle naplnit záznam daty z přicházejícího datareaderu.
		/// Typové čtení zajišťuje mapa, metodou map.GetItem...(string columnName).
		/// Metoda má vracet true = data byla skutečně načtena a do záznamu uložena (false = nedošlo k tomu, data se budou načítat genericky).
		/// </summary>
		/// <param name="reader"></param>
		/// <param name="map"></param>
		/// <returns></returns>
		bool IDbFill.FillFromReader(SqlDataReader reader, FieldMapperLoad map)
		{
			_cislo_template = (int)map.FillDataIntoField<int>("cislo_template", reader);
			_nazev = (string)map.FillDataIntoField<string>("nazev", reader);
			_cislo_tridy = (int)map.FillDataIntoField<int>("cislo_tridy", reader);
			_nazev_dw = (string)map.FillDataIntoField<string>("nazev_dw", reader);
			_nazev_pbl = (string)map.FillDataIntoField<string>("nazev_pbl", reader);
			_priznak_ie = (string)map.FillDataIntoField<string>("priznak_ie", reader);
			_ext_appl = (string)map.FillDataIntoField<string>("ext_appl", reader);
			_typ = (string)map.FillDataIntoField<string>("typ", reader);
			_zam_id = (SqlInt32)map.FillDataIntoField<SqlInt32>("zam_id", reader);
			_rozsah_platnosti = (string)map.FillDataIntoField<string>("rozsah_platnosti", reader);
			_seznam_poradacu = (string)map.FillDataIntoField<string>("seznam_poradacu", reader);
			_popis = (string)map.FillDataIntoField<string>("popis", reader);
			_vztah = (SqlInt32)map.FillDataIntoField<SqlInt32>("vztah", reader);
			_force_async = (string)map.FillDataIntoField<string>("force_async", reader);
			_pocet_kopii = (SqlInt16)map.FillDataIntoField<SqlInt16>("pocet_kopii", reader);
			_auditovat = (string)map.FillDataIntoField<string>("auditovat", reader);
			_pouze_net = (string)map.FillDataIntoField<string>("pouze_net", reader);
			_count_of_use_is_active = (string)map.FillDataIntoField<string>("count_of_use_is_active", reader);
			_startcounting = (SqlDateTime)map.FillDataIntoField<SqlDateTime>("startcounting", reader);
			_stopcounting = (SqlDateTime)map.FillDataIntoField<SqlDateTime>("stopcounting", reader);
			_datum_zmeny = (SqlDateTime)map.FillDataIntoField<SqlDateTime>("datum_zmeny", reader);
			_importtime = (SqlDateTime)map.FillDataIntoField<SqlDateTime>("importtime", reader);
			_evidovane_tisky = (string)map.FillDataIntoField<string>("evidovane_tisky", reader);
			_origin = (string)map.FillDataIntoField<string>("origin", reader);
			_kind = (string)map.FillDataIntoField<string>("kind", reader);
			_help = (string)map.FillDataIntoField<string>("help", reader);
			_bez_kontroly_poctu_zaznamu = (string)map.FillDataIntoField<string>("bez_kontroly_poctu_zaznamu", reader);
			_pouziti_sablony_na_databazi = (string)map.FillDataIntoField<string>("pouziti_sablony_na_databazi", reader);
			_show = (string)map.FillDataIntoField<string>("show", reader);
			_legislative_validity_until = (SqlDateTime)map.FillDataIntoField<SqlDateTime>("legislative_validity_until", reader);
			_rozhrani_tridy = (SqlInt32)map.FillDataIntoField<SqlInt32>("rozhrani_tridy", reader);
			_namespace = (string)map.FillDataIntoField<string>("namespace", reader);
			_tvorba_nazvu_souboru = (string)map.FillDataIntoField<string>("tvorba_nazvu_souboru", reader);
			_sync_id = (string)map.FillDataIntoField<string>("sync_id", reader);
			_lze_aplikovat_do_prehledu = (string)map.FillDataIntoField<string>("lze_aplikovat_do_prehledu", reader);

			// lcs.noris_gs_template:
			_pk = (int)map.FillDataIntoField<int>("pk", reader);
			_cislo_sablony = (SqlInt32)map.FillDataIntoField<SqlInt32>("cislo_sablony", reader);
			_filter_act = (SqlInt32)map.FillDataIntoField<SqlInt32>("filter_act", reader);
			_filter_defa = (SqlInt32)map.FillDataIntoField<SqlInt32>("filter_defa", reader);
			_b_save = (SqlInt16)map.FillDataIntoField<SqlInt16>("b_save", reader);
			_b_distinct = (SqlInt16)map.FillDataIntoField<SqlInt16>("b_distinct", reader);
			_b_enablesort = (SqlInt16)map.FillDataIntoField<SqlInt16>("b_enablesort", reader);
			_b_gridlines = (SqlInt16)map.FillDataIntoField<SqlInt16>("b_gridlines", reader);
			_b_gridlinesprint = (SqlInt16)map.FillDataIntoField<SqlInt16>("b_gridlinesprint", reader);
			_b_ask_print = (SqlInt16)map.FillDataIntoField<SqlInt16>("b_ask_print", reader);
			_b_landscape = (SqlInt16)map.FillDataIntoField<SqlInt16>("b_landscape", reader);
			_b_usegroupdef = (SqlInt16)map.FillDataIntoField<SqlInt16>("b_usegroupdef", reader);
			_s_reportname = (string)map.FillDataIntoField<string>("s_reportname", reader);
			_s_mark = (string)map.FillDataIntoField<string>("s_mark", reader);
			_b_onlygroups = (SqlInt16)map.FillDataIntoField<SqlInt16>("b_onlygroups", reader);
			_b_onlygroup = (SqlInt16)map.FillDataIntoField<SqlInt16>("b_onlygroup", reader);
			_printfont = (string)map.FillDataIntoField<string>("printfont", reader);
			_temlate_size = (string)map.FillDataIntoField<string>("temlate_size", reader);
			_b_printwhere = (Int16)map.FillDataIntoField<Int16>("b_printwhere", reader);
			_b_wrap_title = (string)map.FillDataIntoField<string>("b_wrap_title", reader);
			_b_groupquery = (Int16)map.FillDataIntoField<Int16>("b_groupquery", reader);
			_b_disablesortchange = (Int16)map.FillDataIntoField<Int16>("b_disablesortchange", reader);
			_charts = (string)map.FillDataIntoField<string>("charts", reader);
			_default_view = (SqlInt32)map.FillDataIntoField<SqlInt32>("default_view", reader);

			return true;
		}
		/// <summary>
		/// Metoda, ve které datový objekt připraví podklady pro uložení svých dat do databáze.
		/// Objekt svoje proměnné vloží do exportní mapy prostřednictvím metod map.AddTable(); map.AddColumn();
		/// Pokud objekt chce plnit více tabulek, plní je do mapy postupně, vždy v pořadí {tabulka, sloupce tabulky; další tabulka; sloupce}.
		/// Po naplnění mapy se vrací true.
		/// </summary>
		/// <param name="map"></param>
		/// <returns></returns>
		bool IDbRecord.PrepareSaveData(FieldMapperSave map)
		{ return false; }
		#endregion
		#region Static generátor SQL selectu
		/// <summary>
		/// SQL SELECT pro načtení columnů, odpovídajících této struktuře. Pozor: neobsahuje filtr ani order.
		/// </summary>
		public static string SqlSelect { get { return @"SELECT * FROM lcs.template JOIN lcs.noris_gs_template on lcs.noris_gs_template.cislo_sablony = lcs.template.cislo_template"; } }
		#endregion
		#region OVERRIDES
		/// <summary>
		/// Háček, který je zavolán po načtení dat.
		/// </summary>
		protected override void RetrieveAfter()
		{
			base.RetrieveAfter();
		}
		#endregion
		#region ROZŠÍŘENÍ O DALŠÍ DATA
		/// <summary>
		/// Informace o třídě, pro kterou je šablona vytvořena
		/// </summary>
		public ClassInfo SourceClassData { get { return Repository.Classes[this.CisloTridy]; } }
		#endregion
	}
	#endregion
	#region KONSTANTY NorisClass
	/// <summary>
	/// Norisovské třídy, konstanty
	/// </summary>
	public class NorisClass
	{
		/// <summary>
		/// Číslo třídy Obecná Objednávka = 213
		/// </summary>
		public const int WhObecnaObjednavka = 213;
		/// <summary>
		/// Číslo třídy Obecná Objednávka Potvrzená = 802
		/// </summary>
		public const int WhObecnaObjedPotvrz = 802;
		/// <summary>
		/// Číslo třídy Obecná Poptávka = 214
		/// </summary>
		public const int WhObecnaPoptavka = 214;
	}
	#endregion
}
